/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/ftplibpp/ftplib.h
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************
2
                          ftplib.h  -  description
3
                             -------------------
4
    begin                : Son Jul 27 2003
5
    copyright            : (C) 2013 by magnus kulke
6
    email                : mkulke@gmail.com
7
 ***************************************************************************/
8
9
/***************************************************************************
10
 *                                                                         *
11
 *   This program is free software; you can redistribute it and/or modify  *
12
 *   it under the terms of the GNU Lesser General Public License as        * 
13
 *   published by the Free Software Foundation; either version 2.1 of the  *
14
 *   License, or (at your option) any later version.                       *
15
 *                                                                         *
16
 ***************************************************************************/
17
 
18
/***************************************************************************
19
 * Note: ftplib, on which ftplibpp was originally based upon used to be    *
20
 * licensed as GPL 2.0 software, as of Jan. 26th 2013 its author Thomas    *
21
 * Pfau allowed the distribution of ftplib via LGPL. Thus the license of   *
22
 * ftplibpp changed aswell.                                                *
23
 ***************************************************************************/
24
 
25
#ifndef FTPLIB_H
26
#define FTPLIB_H
27
28
#if defined(_WIN32)
29
30
#if BUILDING_DLL
31
# define DLLIMPORT __declspec (dllexport)
32
#else /* Not BUILDING_DLL */
33
# define DLLIMPORT __declspec (dllimport)
34
#endif /* Not BUILDING_DLL */
35
36
#include <time.h>
37
#endif
38
39
#ifndef _WIN32
40
#include <unistd.h>
41
#include <sys/time.h>
42
#endif
43
44
#ifdef NOLFS
45
#define off64_t long
46
#endif
47
48
#if defined(__APPLE__)
49
#define off64_t __darwin_off_t
50
#define fseeko64 fseeko
51
#define fopen64 fopen
52
#endif
53
54
#ifndef NOSSL
55
#include <openssl/ssl.h>
56
#endif
57
58
#ifndef _FTPLIB_SSL_CLIENT_METHOD_
59
#define _FTPLIB_SSL_CLIENT_METHOD_ TLSv1_2_client_method
60
#endif//_FTPLIB_SSL_CLIENT_METHOD_
61
62
using namespace std;
63
64
/**
65
  *@author mkulke
66
  */
67
68
typedef int (*FtpCallbackXfer)(off64_t xfered, void *arg);
69
typedef int (*FtpCallbackIdle)(void *arg);
70
typedef void (*FtpCallbackLog)(char *str, void* arg, bool out);
71
72
#ifndef NOSSL
73
typedef bool (*FtpCallbackCert)(void *arg, X509 *cert);
74
#endif
75
76
struct ftphandle {
77
  char *cput,*cget;
78
  int handle;
79
  int cavail,cleft;
80
  char *buf;
81
  int dir;
82
  ftphandle *ctrl;
83
  int cmode;
84
  struct timeval idletime;
85
  FtpCallbackXfer xfercb;
86
  FtpCallbackIdle idlecb;
87
  FtpCallbackLog logcb;
88
  void *cbarg;
89
  off64_t xfered;
90
  off64_t cbbytes;
91
  off64_t xfered1;
92
  char response[256];
93
#ifndef NOSSL
94
  SSL* ssl;
95
  SSL_CTX* ctx;
96
  BIO* sbio;
97
  int tlsctrl;
98
  int tlsdata;
99
  FtpCallbackCert certcb;
100
#endif
101
  off64_t offset;
102
  bool correctpasv;
103
};
104
105
#if defined(_WIN32)  
106
class DLLIMPORT ftplib {
107
#else
108
class ftplib {
109
#endif
110
public:
111
112
  enum accesstype
113
  {
114
    dir = 1,
115
    dirverbose,
116
    fileread,
117
    filewrite,
118
    filereadappend,
119
    filewriteappend
120
  }; 
121
122
  enum transfermode
123
  {
124
    ascii = 'A',
125
    image = 'I'
126
  };
127
128
  enum connmode
129
  {
130
    pasv = 1,
131
    port
132
  };
133
134
  enum fxpmethod
135
  {
136
    defaultfxp = 0,
137
        alternativefxp
138
  };
139
140
    enum dataencryption
141
    {
142
        unencrypted = 0,
143
        secure
144
    };
145
146
  ftplib();
147
  ~ftplib();
148
    char* LastResponse();
149
    int Connect(const char *host);
150
    int Login(const char *user, const char *pass);
151
    int Site(const char *cmd);
152
    int Raw(const char *cmd);
153
    int SysType(char *buf, int max);
154
    int Mkdir(const char *path);
155
    int Chdir(const char *path);
156
    int Cdup();
157
    int Rmdir(const char *path);
158
    int Pwd(char *path, int max);
159
    int Nlst(const char *outputfile, const char *path);
160
    int Dir(const char *outputfile, const char *path);
161
    int Size(const char *path, int *size, transfermode mode);
162
    int ModDate(const char *path, char *dt, int max);
163
    int Get(const char *outputfile, const char *path, transfermode mode, off64_t offset = 0);
164
    int Put(const char *inputfile, const char *path, transfermode mode, off64_t offset = 0);
165
    int Rename(const char *src, const char *dst);
166
    int Delete(const char *path);
167
#ifndef NOSSL    
168
  int SetDataEncryption(dataencryption enc);
169
    int NegotiateEncryption();
170
  void SetCallbackCertFunction(FtpCallbackCert pointer);
171
#endif
172
    int Quit();
173
    void SetCallbackIdleFunction(FtpCallbackIdle pointer);
174
    void SetCallbackLogFunction(FtpCallbackLog pointer);
175
  void SetCallbackXferFunction(FtpCallbackXfer pointer);
176
  void SetCallbackArg(void *arg);
177
    void SetCallbackBytes(off64_t bytes);
178
0
  void SetCorrectPasv(bool b) { mp_ftphandle->correctpasv = b; };
179
    void SetCallbackIdletime(int time);
180
    void SetConnmode(connmode mode);
181
    static int Fxp(ftplib* src, ftplib* dst, const char *pathSrc, const char *pathDst, transfermode mode, fxpmethod method);
182
    
183
  ftphandle* RawOpen(const char *path, accesstype type, transfermode mode);
184
  int RawClose(ftphandle* handle); 
185
  int RawWrite(void* buf, int len, ftphandle* handle);
186
  int RawRead(void* buf, int max, ftphandle* handle); 
187
188
private:
189
    ftphandle* mp_ftphandle;
190
191
    int FtpXfer(const char *localfile, const char *path, ftphandle *nControl, accesstype type, transfermode mode);
192
    int FtpOpenPasv(ftphandle *nControl, ftphandle **nData, transfermode mode, int dir, char *cmd);
193
    int FtpSendCmd(const char *cmd, char expresp, ftphandle *nControl);
194
    int FtpAcceptConnection(ftphandle *nData, ftphandle *nControl);
195
    int FtpOpenPort(ftphandle *nControl, ftphandle **nData, transfermode mode, int dir, char *cmd);
196
    int FtpRead(void *buf, int max, ftphandle *nData);
197
    int FtpWrite(void *buf, int len, ftphandle *nData);
198
    int FtpAccess(const char *path, accesstype type, transfermode mode, ftphandle *nControl, ftphandle **nData);
199
    int FtpClose(ftphandle *nData);
200
  
201
  int socket_wait(ftphandle *ctl);
202
    int readline(char *buf,int max,ftphandle *ctl);
203
    int writeline(char *buf, int len, ftphandle *nData);
204
    int readresp(char c, ftphandle *nControl);
205
  
206
  void ClearHandle();
207
  int CorrectPasvResponse(unsigned char *v);
208
};
209
210
#endif
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/Statistic/statistic.h
Line
Count
Source
1
#ifndef STATISTIC_H
2
#define STATISTIC_H
3
#include <iostream>
4
#include <deque>
5
#include <numeric>
6
#include <algorithm>
7
#include <sstream>
8
#include <cmath>
9
#include <vector>
10
11
template <class T>
12
class STATISTIC
13
{
14
public:
15
    STATISTIC(unsigned int size): m_size(size)
16
3.33k
    {
17
3.33k
18
3.33k
    }
_ZN9STATISTICIdEC2Ej
Line
Count
Source
16
3.26k
    {
17
3.26k
18
3.26k
    }
_ZN9STATISTICIiEC2Ej
Line
Count
Source
16
64
    {
17
64
18
64
    }
19
12
    void resize(unsigned int i){
20
12
        if (i < m_size){
21
96
            while(m_dequeue.size()> i){
22
84
                pop_front();
23
84
            }
24
12
        }
25
12
        m_size = i;
26
12
    }
27
316
    T size(){
28
316
        return  static_cast<T>(m_dequeue.size());
29
316
    }
30
40
    void push_front(T v){
31
40
        if (m_dequeue.size() >= m_size){
32
4
            pop_back();
33
4
        }
34
40
        m_dequeue.push_front(v);
35
40
    }
36
2.39k
    void push_back(T v){
37
2.39k
        if (m_dequeue.size() >= m_size){
38
8
            pop_front();
39
8
        }
40
2.39k
        m_dequeue.push_back(v);
41
2.39k
    }
_ZN9STATISTICIdE9push_backEd
Line
Count
Source
36
1.22k
    void push_back(T v){
37
1.22k
        if (m_dequeue.size() >= m_size){
38
8
            pop_front();
39
8
        }
40
1.22k
        m_dequeue.push_back(v);
41
1.22k
    }
_ZN9STATISTICIiE9push_backEi
Line
Count
Source
36
1.16k
    void push_back(T v){
37
1.16k
        if (m_dequeue.size() >= m_size){
38
0
            pop_front();
39
0
        }
40
1.16k
        m_dequeue.push_back(v);
41
1.16k
    }
42
12
    void pop_back(){
43
12
        m_dequeue.pop_back();
44
12
        // std::cout <<"pop_back"<<std::endl;
45
12
    }
46
92
    void pop_front(){
47
92
        m_dequeue.pop_front();
48
92
        // std::cout <<"pop_front"<<std::endl;
49
92
    }
_ZN9STATISTICIdE9pop_frontEv
Line
Count
Source
46
92
    void pop_front(){
47
92
        m_dequeue.pop_front();
48
92
        // std::cout <<"pop_front"<<std::endl;
49
92
    }
Unexecuted instantiation: _ZN9STATISTICIiE9pop_frontEv
50
    ///////////////////////////////////////////// statistic /////////////////////////////
51
52
    T median(){
52
52
        auto backup = m_dequeue;
53
52
        std::sort(backup.begin(), backup.end());
54
52
        if (backup.size() % 2 != 0){
55
20
            return backup[backup.size() / 2];
56
20
        }
57
32
        else{
58
32
            T m = backup[backup.size() / 2] + backup[(backup.size() / 2)-1];
59
32
            return m /2;
60
32
        }
61
52
    }
_ZN9STATISTICIdE6medianEv
Line
Count
Source
51
20
    T median(){
52
20
        auto backup = m_dequeue;
53
20
        std::sort(backup.begin(), backup.end());
54
20
        if (backup.size() % 2 != 0){
55
12
            return backup[backup.size() / 2];
56
12
        }
57
8
        else{
58
8
            T m = backup[backup.size() / 2] + backup[(backup.size() / 2)-1];
59
8
            return m /2;
60
8
        }
61
20
    }
_ZN9STATISTICIiE6medianEv
Line
Count
Source
51
32
    T median(){
52
32
        auto backup = m_dequeue;
53
32
        std::sort(backup.begin(), backup.end());
54
32
        if (backup.size() % 2 != 0){
55
8
            return backup[backup.size() / 2];
56
8
        }
57
24
        else{
58
24
            T m = backup[backup.size() / 2] + backup[(backup.size() / 2)-1];
59
24
            return m /2;
60
24
        }
61
32
    }
62
92
    T sum(){
63
92
        return std::accumulate(m_dequeue.begin(), m_dequeue.end(), static_cast<T>(0));
64
92
    }
65
66
92
    T average(){
67
92
        T av  = sum() /size();
68
92
        return av;
69
92
    }
70
71
20
    T max(){
72
20
        T max = m_dequeue[0];
73
160
        for (auto v : m_dequeue){
74
160
            if (v > max){
75
52
                max = v;
76
52
            }
77
160
        }
78
20
        return max;
79
20
    }
80
81
20
    T min(){
82
20
        T min = m_dequeue[0];
83
160
        for (auto v : m_dequeue){
84
160
            if (v < min){
85
12
                min = v;
86
12
            }
87
160
        }
88
20
        return min;
89
20
    }
90
91
4
    T range(){
92
4
        return max() - min();
93
4
    }
94
95
24
    T standardDeviation(){
96
24
        double standardDeviation = 0.0;
97
24
        T _av = average();
98
24
99
152
        for(int i = 0; i < size(); ++i){
100
128
            standardDeviation += pow(m_dequeue.at(i) - _av, 2);
101
128
        }
102
24
        return sqrt(standardDeviation / size());
103
24
    }
104
105
12
    T coefficientOfVariation(){
106
12
107
12
        return (standardDeviation()/average()) /** 100*/;
108
12
    }
109
110
84
    T mode(){
111
84
112
84
        T _mode = 0;
113
84
        T _modeTemp = 0;
114
84
        int counter = 1;
115
84
        int modeCounter = 1;
116
84
        auto backup = m_dequeue;
117
84
        if(m_dequeue.size() == 1)
118
20
        {
119
20
            return m_dequeue.at(0);
120
20
        }
121
64
        std::sort(backup.begin(), backup.end());
122
64
#ifdef BT_TEST
123
64
        std::cout << " " << std::endl;
124
64
        for (auto i : backup)
125
932
        {
126
932
            std::cout << i << " ";
127
932
        }
128
64
        std::cout << " " << std::endl;
129
64
#endif
130
64
        _mode = _modeTemp = backup.at(0);
131
64
        backup.pop_front();
132
64
        for (auto b : backup)
133
868
        {
134
868
            if (_modeTemp == b)
135
540
            {
136
540
                modeCounter++;
137
540
            }
138
328
            else
139
328
            {
140
328
                _modeTemp = b;
141
328
                modeCounter = 1;
142
328
            }
143
868
144
868
            if(counter < modeCounter)
145
320
            {
146
320
                counter = modeCounter;
147
320
                _mode = _modeTemp;
148
320
            }
149
868
        }
150
64
#ifdef BT_TEST
151
64
        std::cout << " moda: " << _mode << " wystepuje razy " << counter << std::endl;
152
64
#endif
153
64
        return _mode;
154
64
    }
_ZN9STATISTICIdE4modeEv
Line
Count
Source
110
52
    T mode(){
111
52
112
52
        T _mode = 0;
113
52
        T _modeTemp = 0;
114
52
        int counter = 1;
115
52
        int modeCounter = 1;
116
52
        auto backup = m_dequeue;
117
52
        if(m_dequeue.size() == 1)
118
12
        {
119
12
            return m_dequeue.at(0);
120
12
        }
121
40
        std::sort(backup.begin(), backup.end());
122
40
#ifdef BT_TEST
123
40
        std::cout << " " << std::endl;
124
40
        for (auto i : backup)
125
356
        {
126
356
            std::cout << i << " ";
127
356
        }
128
40
        std::cout << " " << std::endl;
129
40
#endif
130
40
        _mode = _modeTemp = backup.at(0);
131
40
        backup.pop_front();
132
40
        for (auto b : backup)
133
316
        {
134
316
            if (_modeTemp == b)
135
60
            {
136
60
                modeCounter++;
137
60
            }
138
256
            else
139
256
            {
140
256
                _modeTemp = b;
141
256
                modeCounter = 1;
142
256
            }
143
316
144
316
            if(counter < modeCounter)
145
32
            {
146
32
                counter = modeCounter;
147
32
                _mode = _modeTemp;
148
32
            }
149
316
        }
150
40
#ifdef BT_TEST
151
40
        std::cout << " moda: " << _mode << " wystepuje razy " << counter << std::endl;
152
40
#endif
153
40
        return _mode;
154
40
    }
_ZN9STATISTICIiE4modeEv
Line
Count
Source
110
32
    T mode(){
111
32
112
32
        T _mode = 0;
113
32
        T _modeTemp = 0;
114
32
        int counter = 1;
115
32
        int modeCounter = 1;
116
32
        auto backup = m_dequeue;
117
32
        if(m_dequeue.size() == 1)
118
8
        {
119
8
            return m_dequeue.at(0);
120
8
        }
121
24
        std::sort(backup.begin(), backup.end());
122
24
#ifdef BT_TEST
123
24
        std::cout << " " << std::endl;
124
24
        for (auto i : backup)
125
576
        {
126
576
            std::cout << i << " ";
127
576
        }
128
24
        std::cout << " " << std::endl;
129
24
#endif
130
24
        _mode = _modeTemp = backup.at(0);
131
24
        backup.pop_front();
132
24
        for (auto b : backup)
133
552
        {
134
552
            if (_modeTemp == b)
135
480
            {
136
480
                modeCounter++;
137
480
            }
138
72
            else
139
72
            {
140
72
                _modeTemp = b;
141
72
                modeCounter = 1;
142
72
            }
143
552
144
552
            if(counter < modeCounter)
145
288
            {
146
288
                counter = modeCounter;
147
288
                _mode = _modeTemp;
148
288
            }
149
552
        }
150
24
#ifdef BT_TEST
151
24
        std::cout << " moda: " << _mode << " wystepuje razy " << counter << std::endl;
152
24
#endif
153
24
        return _mode;
154
24
    }
155
156
    float trend(){
157
        int down = 0;
158
        int eq = 0;
159
        int up = 0;
160
        int lp = 0;
161
        T diff = 0;
162
        T first = m_dequeue[0];
163
164
        for (auto i = 1; i < m_dequeue.size(); ++i){
165
            if (first < m_dequeue[i]){
166
                up++;
167
                if (m_dequeue[i] - first > diff){
168
                    diff = m_dequeue[i] - first;
169
                    lp = i;
170
                }
171
            }
172
            if (first == m_dequeue[i]){ eq++;}
173
            if (first > m_dequeue[i]){
174
                if (diff < first - m_dequeue[i] ){
175
                    diff = first - m_dequeue[i];
176
                    lp = i;
177
                }
178
                down++;
179
            }
180
            first = m_dequeue[i];
181
        }
182
        std::cout <<"up "<<up<<" eq "<< eq << " down "<< down <<" max diff "<< diff<<" lp "<<lp << std::endl;
183
        return 2.2;
184
    }
185
186
80
    bool isMoreDiff(T diff){
187
80
        if (m_dequeue.size()>2){
188
56
            T d = m_dequeue.at( m_dequeue.size()-2)
189
56
                    - m_dequeue.at( m_dequeue.size() - 1);
190
56
            d = fabs(d);
191
56
            if (d > diff && m_alarm == false){
192
24
                m_alarm = true;
193
24
                return true;
194
24
            }
195
32
            if (d <= diff){
196
32
                m_alarm = false;
197
32
                return false;
198
32
            }
199
24
        }
200
24
        return false;
201
24
    }
202
28
    std::pair<double,double> getLast2(){
203
28
        if (m_dequeue.size()>2){
204
24
            return std::make_pair(static_cast<double>(m_dequeue.at( m_dequeue.size()-2)),
205
24
                                  static_cast<double>(m_dequeue.at( m_dequeue.size()-1))    );
206
24
        }
207
4
#ifdef BT_TEST
208
4
        puts("no data - return 0.0 0.0");
209
4
#endif
210
4
        return std::make_pair(0.0,0.0);
211
4
    }
212
213
    /////////////////////////////////////////////////////////////////////////////////////
214
56
    void print(){
215
284
        for(auto n : m_dequeue){
216
284
            std::cout << ","<< n;
217
284
        }
218
56
        std::cout << " " <<std::endl;
219
56
    }
220
221
222
16
    std::string stats(){
223
16
224
16
        std::stringstream ss(" brak danych =(");
225
16
        if(size()>0)
226
12
        {
227
12
            ss.str("");
228
12
            ss <<"rozmiar tablicy: "<< size() <<std::endl
229
12
              << "min: "<< min() <<std::endl
230
12
              << "max: "<< max()<<std::endl
231
12
              << "srednia " << average() <<std::endl
232
12
              << "mediana " << median()  <<std::endl
233
12
              << "odchylenie st "<< standardDeviation() << std::endl
234
12
              << "wspolczynnik zmiennosci " << coefficientOfVariation() <<"%"<< std::endl
235
12
              << "Dominanta " << mode();
236
12
237
12
238
12
            ss << std::endl
239
12
               << "data " <<  std::endl;
240
64
            for(auto n : m_dequeue){
241
64
                ss << "|"<< n;
242
64
            }
243
12
        }
244
16
        ss <<  std::endl;
245
16
        return ss.str();
246
16
    }
247
248
private:
249
    unsigned int m_size;
250
    std::deque <T> m_dequeue;
251
    bool m_alarm = false;
252
};
253
254
#endif // STATISTIC_H
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/Statistic/statistic_test/statistic_BT.cpp
Line
Count
Source
1
#include <gtest/gtest.h>
2
#include <gmock/gmock.h>
3
#include "../statistic.h"
4
5
class StatisticClass_fixture : public ::testing::Test
6
{
7
public:
8
    STATISTIC<double> average;
9
    StatisticClass_fixture(): average(12)
10
28
    {
11
28
    }
12
    void SetUp() final
13
28
    {
14
28
        average.push_back(1);
15
28
        average.push_back(1);
16
28
        average.push_back(2);
17
28
        average.push_back(2);
18
28
        average.push_back(3);
19
28
        average.push_back(3);
20
28
        average.push_back(4);
21
28
        average.push_back(4);
22
28
        average.push_back(-5);
23
28
        average.push_back(-5);
24
28
        average.push_back(6);
25
28
        average.push_back(6);
26
28
    }
27
    void TearDown() final
28
28
    {
29
28
30
28
    }
31
};
32
33
TEST_F(StatisticClass_fixture, range)
34
4
{
35
4
    EXPECT_DOUBLE_EQ(average.average() , 1.8333333333333333);
36
4
    EXPECT_EQ(average.range(), 11);
37
4
}
38
39
TEST_F(StatisticClass_fixture, average)
40
4
{
41
4
    EXPECT_DOUBLE_EQ(average.average() , 1.8333333333333333);
42
4
    std::string ret = average.stats();
43
4
    EXPECT_THAT(ret, testing::HasSubstr("max"));
44
4
}
45
TEST_F(StatisticClass_fixture, averageOne)
46
4
{
47
4
    average.resize(1);
48
4
    average.push_back(1);
49
4
    EXPECT_DOUBLE_EQ(average.average() , 1.0);
50
4
}
51
TEST_F(StatisticClass_fixture, median)
52
4
{
53
4
    EXPECT_EQ(average.median(),2.5f);
54
4
}
55
TEST(StatisticClass, medianOne)
56
4
{
57
4
    STATISTIC<double> average(1);
58
4
    average.push_back(1);
59
4
    EXPECT_EQ(average.median(), 1.0f);
60
4
}
61
TEST_F(StatisticClass_fixture, min)
62
4
{
63
4
    EXPECT_EQ(average.min(),-5.0f);
64
4
}
65
TEST_F(StatisticClass_fixture, max)
66
4
{
67
4
    EXPECT_EQ(average.max(),6);
68
4
}
69
TEST_F(StatisticClass_fixture, push_and_pop)
70
4
{
71
4
    average.pop_back();
72
4
    EXPECT_EQ(average.size(),11);
73
4
    average.push_front(3.9);
74
4
    EXPECT_EQ(average.size(),12);
75
4
    average.pop_back();
76
4
    EXPECT_EQ(average.size(),11);
77
4
}
78
79
TEST(StatisticClass, resize)
80
4
{
81
4
    unsigned int s = 3;
82
4
    STATISTIC<double> average(12);
83
4
    average.push_back(1);
84
4
    average.push_back(2);
85
4
    average.push_back(3);
86
4
    average.push_back(4);
87
4
    average.push_back(5);
88
4
    average.push_front(44);
89
4
    average.push_front(45);
90
4
    average.print();
91
4
    average.resize(s);
92
4
93
4
    EXPECT_EQ(average.size(),static_cast<double>(s));
94
4
95
4
    auto data = average.getLast2();
96
4
    average.print();
97
4
98
4
    EXPECT_EQ(data.first,4.0);
99
4
    EXPECT_EQ(data.second,5.0);
100
4
}
101
102
TEST(StatisticClass, getLast2_empty)
103
4
{
104
4
    unsigned int s = 1;
105
4
    STATISTIC<double> average(12);
106
4
    average.push_back(1);
107
4
    average.push_back(2);
108
4
    average.push_back(3);
109
4
    average.push_back(4);
110
4
    average.push_back(5);
111
4
    average.push_front(44);
112
4
    average.push_front(45);
113
4
    average.print();
114
4
    average.resize(s);
115
4
    average.push_front(33);
116
4
117
4
    EXPECT_EQ(average.size(),static_cast<double>(s));
118
4
119
4
    auto data = average.getLast2();
120
4
    average.print();
121
4
122
4
    EXPECT_EQ(data.first,0.0);
123
4
    EXPECT_EQ(data.second,0.0);
124
4
}
125
126
TEST(StatisticClass, moreDiff)
127
4
{
128
4
    STATISTIC<double> average(12);
129
4
    average.push_back(1);
130
4
    average.push_back(2);
131
4
    average.push_back(30);
132
4
    average.push_back(4);
133
4
    average.push_back(5);
134
4
    average.push_front(44);
135
4
    average.push_front(45);
136
4
    average.print();
137
4
138
4
    EXPECT_FALSE(average.isMoreDiff(2.2));
139
4
140
4
    average.push_back(7.3);
141
4
    average.print();
142
4
143
4
    EXPECT_TRUE(average.isMoreDiff(2.2));
144
4
}
145
146
TEST(StatisticClass, moreDiff_wrong)
147
4
{
148
4
    STATISTIC<double> average(1);
149
4
    average.push_back(1);
150
4
151
4
    average.print();
152
4
153
4
    EXPECT_FALSE(average.isMoreDiff(2.2));
154
4
155
4
    average.push_back(7.3);
156
4
    average.print();
157
4
158
4
    EXPECT_FALSE(average.isMoreDiff(2.2));
159
4
}
160
161
TEST(StatisticClass, noMoreDiff)
162
4
{
163
4
    STATISTIC<double> average(12);
164
4
    average.push_back(1);
165
4
    average.push_back(2);
166
4
    average.push_back(30);
167
4
    average.push_back(4);
168
4
    average.push_back(5);
169
4
    average.push_front(44);
170
4
    average.push_front(45);
171
4
    average.print();
172
4
173
4
    EXPECT_FALSE(average.isMoreDiff(6.2));
174
4
175
4
    average.push_back(7.3);
176
4
    average.print();
177
4
178
4
    EXPECT_FALSE(average.isMoreDiff(9.2));
179
4
}
180
181
TEST(StatisticClass, mode)
182
4
{
183
4
    STATISTIC<double> average(22);
184
4
    average.push_back(29.62);
185
4
    average.push_back(29.71);
186
4
    average.push_back(30.19);
187
4
    average.push_back(33.5);
188
4
    average.push_back(30.31);
189
4
    average.push_back(30.81);
190
4
    average.push_back(30.87);
191
4
    average.push_back(31.25);
192
4
    average.push_back(31.31);
193
4
    average.push_back(31.56);
194
4
    average.push_back(31.87);
195
4
    average.push_back(31.94);
196
4
    average.push_back(32.13);
197
4
    average.push_back(32.13);  //to
198
4
    average.push_back(32.63);
199
4
200
4
    average.print();
201
4
    std::cout << "1 MODE: " << average.mode() << std::endl;
202
8
    EXPECT_DOUBLE_EQ(32.13,average.mode()) << "ZLA DOMINANTA 32.13";
203
4
    average.push_back(33.5);
204
4
    average.push_back(33.5);
205
4
    std::cout << "2 MODE: " << average.mode() << std::endl;
206
8
    EXPECT_DOUBLE_EQ(33.5,average.mode()) << "ZLA DOMINANTA 33.5";
207
4
}
208
TEST(StatisticClass, modeOne)
209
4
{
210
4
    STATISTIC<double> average(1);
211
4
    average.push_back(29.62);
212
4
    average.print();
213
4
    std::cout << "1 MODE: " << average.mode() << std::endl;
214
8
    EXPECT_DOUBLE_EQ(29.62,average.mode()) << "ZLA DOMINANTA 32.13";
215
4
}
216
TEST(StatisticClass, modeTwo)
217
4
{
218
4
    STATISTIC<double> average(10);
219
4
    average.push_back(29.62);
220
4
    average.push_back(28.62);
221
4
    average.print();
222
4
    std::cout << "1 MODE: " << average.mode() << std::endl;
223
8
    EXPECT_DOUBLE_EQ(28.62,average.mode()) << "ZLA DOMINANTA 32.13";
224
4
}
225
TEST(StatisticClass, modeThree)
226
4
{
227
4
    STATISTIC<double> average(10);
228
4
    average.push_back(29.62);
229
4
    average.push_back(28.62);
230
4
    average.push_back(29.63);
231
4
    average.print();
232
4
    std::cout << "1 MODE: " << average.mode() << std::endl;
233
8
    EXPECT_DOUBLE_EQ(28.62,average.mode()) << "ZLA DOMINANTA 32.13";
234
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/emoji/emoji.cpp
Line
Count
Source (jump to first uncovered line)
1
#include <sstream>
2
#include "emoji.h"
3
4
EMOJI::EMOJI()
5
0
{
6
0
7
0
}
8
9
std::string EMOJI::emoji(E_emoji e)
10
104
{
11
104
    switch (e) {
12
104
    case E_emoji::NORTH_EAST_ARROW:
13
64
        return HEX_STR::hexToStr("E28697");
14
104
    case E_emoji::SOUTH_EAST_ARROW:
15
12
        return HEX_STR::hexToStr("E28698");
16
104
    case E_emoji::NORTH_WEST_ARROW:
17
0
        return HEX_STR::hexToStr("E28696");
18
104
    case E_emoji::SOUTH_WEST_ARROW:
19
0
        return HEX_STR::hexToStr("E28699");
20
104
    case E_emoji::LEFT_RIGHT_ARROW:
21
0
        return HEX_STR::hexToStr("E28694");
22
104
    case E_emoji::UP_DOWN_ARROW:
23
0
        return HEX_STR::hexToStr("E28695");
24
104
    case E_emoji::ALARM_CLOCK:
25
0
        return HEX_STR::hexToStr("E28FB0");
26
104
    case E_emoji::SUN_WITH_FACE:
27
0
        return HEX_STR::hexToStr("F09F8C9E");
28
104
    case E_emoji::SNOWFLAKE:
29
0
        return HEX_STR::hexToStr("E29D84");
30
104
    case E_emoji::HEAVY_BLACK_HEART:
31
0
        return HEX_STR::hexToStr("E29DA4");
32
104
    case E_emoji::WARNING_SIGN:
33
4
        return HEX_STR::hexToStr("E29AA0");
34
104
    case E_emoji::CHART_WITH_DOWNWARDS_TREND:
35
8
        return HEX_STR::hexToStr("F09F9389");
36
104
    case E_emoji::CHART_WITH_UPWARDS_TREND:
37
8
        return HEX_STR::hexToStr("F09F9388");
38
104
    case E_emoji::THUNDER_CLOUD_AND_RAIN:
39
8
        return HEX_STR::hexToStr("E29B88");
40
0
41
0
    }
42
0
    return"ok";
43
0
}
44
45
std::string HEX_STR::hexToStr(const std::string& hex)
46
104
{
47
104
    std::string res;
48
104
    res.reserve(hex.size() / 2);
49
432
    for (unsigned int i = 0; i < hex.size(); i += 2)
50
328
    {
51
328
        std::istringstream iss(hex.substr(i, 2));
52
328
        int temp;
53
328
        iss >> std::hex >> temp;
54
328
        res += static_cast<char>(temp);
55
328
    }
56
104
    return res;
57
104
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/event_counters/event/event_command.cpp
Line
Count
Source
1
#include "event_command.h"
2
3
event_command::event_command(const std::string& name):  event_counters(name)
4
848
{
5
848
6
848
}
7
8
std::string event_command::help()
9
12
{
10
12
    return "event command";
11
12
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/event_counters/event/event_mpd.cpp
Line
Count
Source
1
#include "event_mpd.h"
2
3
event_mpd::event_mpd(const std::string& name): event_counters(name)
4
848
{
5
848
6
848
}
7
8
std::string event_mpd::help()
9
8
{
10
8
    return "event from MPD";
11
8
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/event_counters/event/event_pilot.cpp
Line
Count
Source
1
#include "event_pilot.h"
2
3
event_pilot::event_pilot(const std::string& name): event_counters(name)
4
848
{
5
848
6
848
}
7
8
std::string event_pilot::help()
9
12
{
10
12
    return "pilot events";
11
12
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/event_counters/event/event_unknown.cpp
Line
Count
Source
1
#include "event_unknown.h"
2
3
event_unknown::event_unknown(const std::string& name) : event_counters(name), name(name)
4
1.05k
{
5
1.05k
6
1.05k
}
7
8
std::string event_unknown::help()
9
152
{
10
152
    return  name+" event";
11
152
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/event_counters/event/new_connect_event.cpp
Line
Count
Source
1
#include "new_connect_event.h"
2
#include <iostream>
3
new_Connect_Event::new_Connect_Event(const std::string& name) : event_counters(name)
4
848
{
5
848
6
848
}
7
8
new_Connect_Event::~new_Connect_Event()
9
848
{
10
848
    std::cout << " kasujemy obiekt" << std::endl;
11
848
}
12
13
std::string new_Connect_Event::help()
14
12
{
15
12
    return "connection start event";
16
12
}
17
18
19
20
21
22
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/event_counters/event_counters.cpp
Line
Count
Source
1
#include "event_counters.h"
2
#include <iostream>
3
#include <iomanip>
4
#include <ctime>
5
#include <sstream>
6
#include <string>
7
#include <algorithm>
8
9
event_counters::event_counters(std::string name) : eventName(std::move(name))
10
4.44k
{
11
4.44k
12
4.44k
}
13
14
int event_counters::howManyEvent()
15
168
{
16
168
    std::lock_guard < std::mutex > lock ( eventMutex);
17
168
    return static_cast<int>( eventList.size() );
18
168
}
19
20
void event_counters::addEvent(const std::string& note)
21
20.4k
{
22
20.4k
    eventStruct d;
23
20.4k
    std::ostringstream oss;
24
20.4k
25
20.4k
    auto t = std::time(nullptr);
26
20.4k
    auto tm = *std::localtime(&t);
27
20.4k
    oss << std::put_time(&tm, "%d-%m-%Y %H:%M:%S");
28
20.4k
29
20.4k
    d.date = oss.str();
30
20.4k
    d.note = note;
31
20.4k
    d.posixTime = static_cast<unsigned int> (std::time(nullptr));
32
20.4k
    std::lock_guard < std::mutex > lock ( eventMutex);
33
20.4k
    eventList.push_back(d);
34
20.4k
}
35
36
std::string event_counters::getEvent()
37
148
{
38
148
    std::stringstream ret;
39
148
    ret << "Event: " << help() << "\n";
40
148
    std::lock_guard <std::mutex> lock(eventMutex);
41
148
    int k =0;
42
33.1k
    for (auto i : eventList){
43
33.1k
        ret << ++k << "\t" << i.date << "     " <<  i.note << "\n";
44
33.1k
    }
45
148
    ret << "\n event per last minute: " << getLast1minNumberEvent_NO_Mutex() << "\n------------------------------";
46
148
    return ret.str();
47
148
}
48
49
void event_counters::clearEvent()
50
12
{
51
12
    std::lock_guard <std::mutex> lock(eventMutex);
52
12
    eventList.clear();
53
12
}
54
55
void event_counters::clearEvent(unsigned int from, unsigned int to)
56
20
{
57
20
    if (to < from){
58
4
        return;
59
4
    }
60
16
    auto max = static_cast<unsigned int>( eventList.size() );
61
16
62
16
    if (max < to){
63
8
        to = max;
64
8
    }
65
16
    if(max<from){
66
4
        from = max;
67
4
        to = max;
68
4
    }
69
16
    std::lock_guard <std::mutex> lock(eventMutex);
70
16
    eventList.erase(eventList.begin()+from, eventList.begin()+to);
71
16
}
72
73
unsigned int event_counters::getLast1minNumberEvent()
74
52
{
75
52
    std::lock_guard <std::mutex> lock(eventMutex);
76
52
    return getLast1minNumberEvent_NO_Mutex();
77
52
}
78
79
std::string event_counters::getEventName()
80
4.44k
{
81
4.44k
    return eventName;
82
4.44k
}
83
84
unsigned int event_counters::getLast1minNumberEvent_NO_Mutex()
85
200
{
86
200
    unsigned int k = 0;
87
200
    if (eventList.empty())
88
12
        return k;
89
188
    unsigned int lastPosix = static_cast<unsigned int> (std::time(nullptr));// eventList.at(eventList.size()-1).posixTime;
90
188
91
35.4k
    for (auto i = eventList.size()-1; i != -1; i--)
92
35.3k
    {
93
35.3k
        if(eventList.at(i).posixTime+60 > lastPosix)
94
35.3k
            k++;
95
4
        else
96
4
            break;
97
35.3k
    }
98
188
    return k;
99
188
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/event_counters/event_counters_handler.cpp
Line
Count
Source
1
#include "event_counters_handler.h"
2
#include "event/new_connect_event.h"
3
#include "event/event_unknown.h"
4
#include "event/event_mpd.h"
5
#include "event/event_pilot.h"
6
#include "event/event_command.h"
7
8
9
event_counters_handler::event_counters_handler()
10
848
{
11
848
    std::shared_ptr <event_counters> newConnectEvent (new new_Connect_Event("connections") );
12
848
    eventCountersMap.insert( std::make_pair( newConnectEvent->getEventName(), newConnectEvent ) );
13
848
14
848
    std::shared_ptr <event_counters> newUnknownEvent (new event_unknown("unknown") );
15
848
    eventCountersMap.insert( std::make_pair( newUnknownEvent->getEventName(), newUnknownEvent ) );
16
848
17
848
    std::shared_ptr <event_counters> eventMPD (new event_mpd("mpd") );
18
848
    eventCountersMap.insert( std::make_pair( eventMPD->getEventName(), eventMPD ) );
19
848
20
848
    std::shared_ptr <event_counters> eventPilot (new event_pilot("pilot") );
21
848
    eventCountersMap.insert( std::make_pair( eventPilot->getEventName(), eventPilot ) );
22
848
23
848
    std::shared_ptr <event_counters> eventCommand (new event_command("command") );
24
848
    eventCountersMap.insert( std::make_pair( eventCommand->getEventName(), eventCommand ) );
25
848
}
26
27
std::shared_ptr<event_counters> event_counters_handler::run(const std::string& name)
28
20.8k
{
29
20.8k
30
20.8k
    if (eventCountersMap.find(name) == eventCountersMap.end()){
31
208
        addEvent(name);
32
208
    }
33
20.8k
    return eventCountersMap[name];
34
20.8k
}
35
36
std::string event_counters_handler::getListPossibleEvents()
37
8
{
38
8
    std::string result;
39
8
40
52
    for( auto iter= eventCountersMap.begin();iter != eventCountersMap.end(); ++iter ) {
41
44
        result+= iter->first;
42
44
        result+= "\n";
43
44
    }
44
8
    return result;
45
8
}
46
47
std::string event_counters_handler::help(const std::string& name)
48
12
{
49
12
    std::string result;
50
12
51
12
    if (name.empty()){
52
52
        for( auto iter= eventCountersMap.begin();iter != eventCountersMap.end(); ++iter ) {
53
44
            result+= iter->second->help();
54
44
            result+= "\n------------------------------\n";
55
44
        }
56
8
    }
57
4
    else{
58
4
        result = eventCountersMap[name]->help();
59
4
    }
60
12
61
12
    return result;
62
12
}
63
std::mutex event_counters_handler::echMutex;
64
65
void event_counters_handler::addEvent(const std::string& name)
66
208
{
67
208
    std::lock_guard <std::mutex> lock(event_counters_handler::echMutex);
68
208
    std::shared_ptr <event_counters> newUnknownEvent (new event_unknown(name) );
69
208
    eventCountersMap.insert( std::make_pair( newUnknownEvent->getEventName(), newUnknownEvent ) );
70
208
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/event_counters/test/event_BT.cpp
Line
Count
Source
1
#include <gtest/gtest.h>
2
#include "test_data.h"
3
#include "../../../iDom_server_OOP/src/iDomTools/test/iDomTools_fixture.h"
4
#include "../event_counters_handler.h"
5
6
class event_counter_fixture : public iDomTOOLS_ClassTest
7
{
8
public:
9
     event_counters_handler mainEvent;
10
     std::string msg = "info";
11
     std::string testEvent = "testEvent";
12
20
     void preper1001Event(){
13
20
         int counter = 1000;
14
20
         EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),0);
15
20
         mainEvent.run(testEvent)->addEvent(msg);
16
20
         EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),1);
17
20
         std::string returnedString = mainEvent.run(testEvent)->getEvent();
18
20
         EXPECT_THAT(returnedString, testing::HasSubstr(msg));
19
20
         EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),1);
20
20
21
20.0k
         for (int i = 1; i!= counter; counter--)
22
19.9k
         {
23
19.9k
             mainEvent.run(testEvent)->addEvent(msg);
24
19.9k
             if(counter == 500)
25
20
                 mainEvent.run(testEvent)->addEvent("cyniu");
26
19.9k
         }
27
20
         EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),1001);
28
20
         returnedString = mainEvent.run(testEvent)->getEvent();
29
20
         EXPECT_THAT(returnedString, testing::HasSubstr("cyniu"));
30
20
     }
31
};
32
33
TEST_F(event_counter_fixture, add_get_clear_event)
34
4
{
35
4
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),0);
36
4
    mainEvent.run(testEvent)->addEvent(msg);
37
4
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),1);
38
4
    std::string returnedString = mainEvent.run(testEvent)->getEvent();
39
4
    EXPECT_THAT(returnedString, testing::HasSubstr(msg));
40
4
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),1);
41
4
    mainEvent.run(testEvent)->clearEvent();
42
4
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),0);
43
4
}
44
45
TEST_F(event_counter_fixture, clear_middle_part_of_event_small_big)
46
4
{
47
4
    preper1001Event();
48
4
    mainEvent.run(testEvent)->clearEvent(400,600);
49
4
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),801);
50
4
    std::string returnedString = mainEvent.run(testEvent)->getEvent();
51
4
    EXPECT_THAT(returnedString, testing::Not(testing::HasSubstr("cyniu")));
52
4
}
53
54
TEST_F(event_counter_fixture, clear_middle_part_of_event_big_small)
55
4
{
56
4
    preper1001Event();
57
4
    mainEvent.run(testEvent)->clearEvent(600,400);
58
4
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),1001);
59
4
    std::string returnedString = mainEvent.run(testEvent)->getEvent();
60
4
    EXPECT_THAT(returnedString,testing::HasSubstr("cyniu"));
61
4
}
62
63
TEST_F(event_counter_fixture, clear_middle_part_of_event_to_max)
64
4
{
65
4
    preper1001Event();
66
4
    mainEvent.run(testEvent)->clearEvent(400,1600);
67
4
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),400);
68
4
    std::string returnedString = mainEvent.run(testEvent)->getEvent();
69
4
    EXPECT_THAT(returnedString, testing::Not(testing::HasSubstr("cyniu")));
70
4
}
71
72
TEST_F(event_counter_fixture, clear_middle_part_of_event_from_max)
73
4
{
74
4
    preper1001Event();
75
4
    mainEvent.run(testEvent)->clearEvent(1400,1600);
76
4
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),1001);
77
4
    std::string returnedString = mainEvent.run(testEvent)->getEvent();
78
4
    EXPECT_THAT(returnedString, testing::HasSubstr("cyniu") );
79
4
}
80
81
TEST_F(event_counter_fixture, getListPossibleEvents)
82
4
{
83
4
    mainEvent.run("INFO")->addEvent("kokolino");
84
4
   std::string returnedString = mainEvent.getListPossibleEvents();
85
4
   std::cout << "wynik: " << returnedString << std::endl;
86
4
   EXPECT_THAT(returnedString, testing::HasSubstr("INFO") );
87
4
}
88
89
TEST_F(event_counter_fixture, getHelp)
90
4
{
91
4
   mainEvent.run("INFO")->addEvent("kokolino");
92
4
   std::string returnedString = mainEvent.help("connections");
93
4
   std::cout << "wynik: " << returnedString << std::endl;
94
4
   EXPECT_THAT(returnedString, testing::HasSubstr("start") );
95
4
   returnedString = mainEvent.help("");
96
4
   std::cout << "wynik: " << returnedString << std::endl;
97
4
   EXPECT_THAT(returnedString, testing::HasSubstr("pilot") );
98
4
}
99
100
TEST_F(event_counter_fixture, getLast1minNumberEvent)
101
4
{
102
4
    preper1001Event();
103
4
    mainEvent.run(testEvent)->eventList.at(500).posixTime -= 65;
104
4
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),1001);
105
4
    EXPECT_EQ(mainEvent.run(testEvent)->getLast1minNumberEvent(),500);
106
4
}
107
TEST_F(event_counter_fixture, getLast1minNumberEventWhenEmpty)
108
4
{
109
4
    EXPECT_EQ(mainEvent.run(testEvent)->howManyEvent(),0);
110
4
    EXPECT_EQ(mainEvent.run(testEvent)->getLast1minNumberEvent(),0);
111
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/json/single_include/nlohmann/json.hpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
    __ _____ _____ _____
3
 __|  |   __|     |   | |  JSON for Modern C++
4
|  |  |__   |  |  | | | |  version 3.2.0
5
|_____|_____|_____|_|___|  https://github.com/nlohmann/json
6
7
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
8
SPDX-License-Identifier: MIT
9
Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.
10
11
Permission is hereby  granted, free of charge, to any  person obtaining a copy
12
of this software and associated  documentation files (the "Software"), to deal
13
in the Software  without restriction, including without  limitation the rights
14
to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
15
copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
16
furnished to do so, subject to the following conditions:
17
18
The above copyright notice and this permission notice shall be included in all
19
copies or substantial portions of the Software.
20
21
THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
22
IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
23
FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
24
AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
25
LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
27
SOFTWARE.
28
*/
29
30
#ifndef NLOHMANN_JSON_HPP
31
#define NLOHMANN_JSON_HPP
32
33
#define NLOHMANN_JSON_VERSION_MAJOR 3
34
#define NLOHMANN_JSON_VERSION_MINOR 2
35
#define NLOHMANN_JSON_VERSION_PATCH 0
36
37
#include <algorithm> // all_of, find, for_each
38
#include <cassert> // assert
39
#include <ciso646> // and, not, or
40
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
41
#include <functional> // hash, less
42
#include <initializer_list> // initializer_list
43
#include <iosfwd> // istream, ostream
44
#include <iterator> // iterator_traits, random_access_iterator_tag
45
#include <numeric> // accumulate
46
#include <string> // string, stoi, to_string
47
#include <utility> // declval, forward, move, pair, swap
48
49
// #include <nlohmann/json_fwd.hpp>
50
#ifndef NLOHMANN_JSON_FWD_HPP
51
#define NLOHMANN_JSON_FWD_HPP
52
53
#include <cstdint> // int64_t, uint64_t
54
#include <map> // map
55
#include <memory> // allocator
56
#include <string> // string
57
#include <vector> // vector
58
59
/*!
60
@brief namespace for Niels Lohmann
61
@see https://github.com/nlohmann
62
@since version 1.0.0
63
*/
64
namespace nlohmann
65
{
66
/*!
67
@brief default JSONSerializer template argument
68
69
This serializer ignores the template arguments and uses ADL
70
([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
71
for serialization.
72
*/
73
template<typename T = void, typename SFINAE = void>
74
struct adl_serializer;
75
76
template<template<typename U, typename V, typename... Args> class ObjectType =
77
         std::map,
78
         template<typename U, typename... Args> class ArrayType = std::vector,
79
         class StringType = std::string, class BooleanType = bool,
80
         class NumberIntegerType = std::int64_t,
81
         class NumberUnsignedType = std::uint64_t,
82
         class NumberFloatType = double,
83
         template<typename U> class AllocatorType = std::allocator,
84
         template<typename T, typename SFINAE = void> class JSONSerializer =
85
         adl_serializer>
86
class basic_json;
87
88
/*!
89
@brief JSON Pointer
90
91
A JSON pointer defines a string syntax for identifying a specific value
92
within a JSON document. It can be used with functions `at` and
93
`operator[]`. Furthermore, JSON pointers are the base for JSON patches.
94
95
@sa [RFC 6901](https://tools.ietf.org/html/rfc6901)
96
97
@since version 2.0.0
98
*/
99
template<typename BasicJsonType>
100
class json_pointer;
101
102
/*!
103
@brief default JSON class
104
105
This type is the default specialization of the @ref basic_json class which
106
uses the standard template types.
107
108
@since version 1.0.0
109
*/
110
using json = basic_json<>;
111
}
112
113
#endif
114
115
// #include <nlohmann/detail/macro_scope.hpp>
116
117
118
// This file contains all internal macro definitions
119
// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them
120
121
// exclude unsupported compilers
122
#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)
123
    #if defined(__clang__)
124
        #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
125
            #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
126
        #endif
127
    #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
128
        #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
129
            #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
130
        #endif
131
    #endif
132
#endif
133
134
// disable float-equal warnings on GCC/clang
135
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
136
    #pragma GCC diagnostic push
137
    #pragma GCC diagnostic ignored "-Wfloat-equal"
138
#endif
139
140
// disable documentation warnings on clang
141
#if defined(__clang__)
142
    #pragma GCC diagnostic push
143
    #pragma GCC diagnostic ignored "-Wdocumentation"
144
#endif
145
146
// allow for portable deprecation warnings
147
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
148
    #define JSON_DEPRECATED __attribute__((deprecated))
149
#elif defined(_MSC_VER)
150
    #define JSON_DEPRECATED __declspec(deprecated)
151
#else
152
    #define JSON_DEPRECATED
153
#endif
154
155
// allow to disable exceptions
156
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
157
8
    #define JSON_THROW(exception) throw exception
158
51.3k
    #define JSON_TRY try
159
    #define JSON_CATCH(exception) catch(exception)
160
    #define JSON_INTERNAL_CATCH(exception) catch(exception)
161
#else
162
    #define JSON_THROW(exception) std::abort()
163
    #define JSON_TRY if(true)
164
    #define JSON_CATCH(exception) if(false)
165
    #define JSON_INTERNAL_CATCH(exception) if(false)
166
#endif
167
168
// override exception macros
169
#if defined(JSON_THROW_USER)
170
    #undef JSON_THROW
171
    #define JSON_THROW JSON_THROW_USER
172
#endif
173
#if defined(JSON_TRY_USER)
174
    #undef JSON_TRY
175
    #define JSON_TRY JSON_TRY_USER
176
#endif
177
#if defined(JSON_CATCH_USER)
178
    #undef JSON_CATCH
179
    #define JSON_CATCH JSON_CATCH_USER
180
    #undef JSON_INTERNAL_CATCH
181
    #define JSON_INTERNAL_CATCH JSON_CATCH_USER
182
#endif
183
#if defined(JSON_INTERNAL_CATCH_USER)
184
    #undef JSON_INTERNAL_CATCH
185
    #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
186
#endif
187
188
// manual branch prediction
189
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
190
36.9M
    #define JSON_LIKELY(x)      __builtin_expect(!!(x), 1)
191
4.80M
    #define JSON_UNLIKELY(x)    __builtin_expect(!!(x), 0)
192
#else
193
    #define JSON_LIKELY(x)      x
194
    #define JSON_UNLIKELY(x)    x
195
#endif
196
197
// C++ language standard detection
198
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
199
    #define JSON_HAS_CPP_17
200
    #define JSON_HAS_CPP_14
201
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
202
    #define JSON_HAS_CPP_14
203
#endif
204
205
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
206
// may be removed in the future once the class is split.
207
208
#define NLOHMANN_BASIC_JSON_TPL_DECLARATION                                \
209
    template<template<typename, typename, typename...> class ObjectType,   \
210
             template<typename, typename...> class ArrayType,              \
211
             class StringType, class BooleanType, class NumberIntegerType, \
212
             class NumberUnsignedType, class NumberFloatType,              \
213
             template<typename> class AllocatorType,                       \
214
             template<typename, typename = void> class JSONSerializer>
215
216
#define NLOHMANN_BASIC_JSON_TPL                                            \
217
    basic_json<ObjectType, ArrayType, StringType, BooleanType,             \
218
    NumberIntegerType, NumberUnsignedType, NumberFloatType,                \
219
    AllocatorType, JSONSerializer>
220
221
// #include <nlohmann/detail/meta/cpp_future.hpp>
222
223
224
#include <ciso646> // not
225
#include <cstddef> // size_t
226
#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
227
228
namespace nlohmann
229
{
230
namespace detail
231
{
232
// alias templates to reduce boilerplate
233
template<bool B, typename T = void>
234
using enable_if_t = typename std::enable_if<B, T>::type;
235
236
template<typename T>
237
using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
238
239
// implementation of C++14 index_sequence and affiliates
240
// source: https://stackoverflow.com/a/32223343
241
template<std::size_t... Ints>
242
struct index_sequence
243
{
244
    using type = index_sequence;
245
    using value_type = std::size_t;
246
    static constexpr std::size_t size() noexcept
247
    {
248
        return sizeof...(Ints);
249
    }
250
};
251
252
template<class Sequence1, class Sequence2>
253
struct merge_and_renumber;
254
255
template<std::size_t... I1, std::size_t... I2>
256
struct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>
257
        : index_sequence < I1..., (sizeof...(I1) + I2)... > {};
258
259
template<std::size_t N>
260
struct make_index_sequence
261
    : merge_and_renumber < typename make_index_sequence < N / 2 >::type,
262
      typename make_index_sequence < N - N / 2 >::type > {};
263
264
template<> struct make_index_sequence<0> : index_sequence<> {};
265
template<> struct make_index_sequence<1> : index_sequence<0> {};
266
267
template<typename... Ts>
268
using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
269
270
// dispatch utility (taken from ranges-v3)
271
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
272
template<> struct priority_tag<0> {};
273
274
// taken from ranges-v3
275
template<typename T>
276
struct static_const
277
{
278
    static constexpr T value{};
279
};
280
281
template<typename T>
282
constexpr T static_const<T>::value;
283
}
284
}
285
286
// #include <nlohmann/detail/meta/type_traits.hpp>
287
288
289
#include <ciso646> // not
290
#include <limits> // numeric_limits
291
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
292
#include <utility> // declval
293
294
// #include <nlohmann/json_fwd.hpp>
295
296
// #include <nlohmann/detail/meta/cpp_future.hpp>
297
298
// #include <nlohmann/detail/meta/detected.hpp>
299
300
301
#include <type_traits>
302
303
// #include <nlohmann/detail/meta/void_t.hpp>
304
305
306
namespace nlohmann
307
{
308
namespace detail
309
{
310
template <typename ...Ts> struct make_void
311
{
312
    using type = void;
313
};
314
template <typename ...Ts> using void_t = typename make_void<Ts...>::type;
315
}
316
}
317
318
319
// http://en.cppreference.com/w/cpp/experimental/is_detected
320
namespace nlohmann
321
{
322
namespace detail
323
{
324
struct nonesuch
325
{
326
    nonesuch() = delete;
327
    ~nonesuch() = delete;
328
    nonesuch(nonesuch const&) = delete;
329
    void operator=(nonesuch const&) = delete;
330
};
331
332
template <class Default,
333
          class AlwaysVoid,
334
          template <class...> class Op,
335
          class... Args>
336
struct detector
337
{
338
    using value_t = std::false_type;
339
    using type = Default;
340
};
341
342
template <class Default, template <class...> class Op, class... Args>
343
struct detector<Default, void_t<Op<Args...>>, Op, Args...>
344
{
345
    using value_t = std::true_type;
346
    using type = Op<Args...>;
347
};
348
349
template <template <class...> class Op, class... Args>
350
using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;
351
352
template <template <class...> class Op, class... Args>
353
using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
354
355
template <class Default, template <class...> class Op, class... Args>
356
using detected_or = detector<Default, void, Op, Args...>;
357
358
template <class Default, template <class...> class Op, class... Args>
359
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
360
361
template <class Expected, template <class...> class Op, class... Args>
362
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
363
364
template <class To, template <class...> class Op, class... Args>
365
using is_detected_convertible =
366
    std::is_convertible<detected_t<Op, Args...>, To>;
367
}
368
}
369
370
// #include <nlohmann/detail/macro_scope.hpp>
371
372
373
namespace nlohmann
374
{
375
/*!
376
@brief detail namespace with internal helper functions
377
378
This namespace collects functions that should not be exposed,
379
implementations of some @ref basic_json methods, and meta-programming helpers.
380
381
@since version 2.1.0
382
*/
383
namespace detail
384
{
385
/////////////
386
// helpers //
387
/////////////
388
389
template<typename> struct is_basic_json : std::false_type {};
390
391
NLOHMANN_BASIC_JSON_TPL_DECLARATION
392
struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};
393
394
//////////////////////////
395
// aliases for detected //
396
//////////////////////////
397
398
template <typename T>
399
using mapped_type_t = typename T::mapped_type;
400
401
template <typename T>
402
using key_type_t = typename T::key_type;
403
404
template <typename T>
405
using value_type_t = typename T::value_type;
406
407
template <typename T>
408
using difference_type_t = typename T::difference_type;
409
410
template <typename T>
411
using pointer_t = typename T::pointer;
412
413
template <typename T>
414
using reference_t = typename T::reference;
415
416
template <typename T>
417
using iterator_category_t = typename T::iterator_category;
418
419
template <typename T>
420
using iterator_t = typename T::iterator;
421
422
template <typename T, typename... Args>
423
using to_json_function = decltype(T::to_json(std::declval<Args>()...));
424
425
template <typename T, typename... Args>
426
using from_json_function = decltype(T::from_json(std::declval<Args>()...));
427
428
///////////////////
429
// is_ functions //
430
///////////////////
431
432
template <typename T, typename = void>
433
struct is_iterator_traits : std::false_type {};
434
435
template <typename T>
436
struct is_iterator_traits<std::iterator_traits<T>>
437
{
438
  private:
439
    using traits = std::iterator_traits<T>;
440
441
  public:
442
    static constexpr auto value =
443
        is_detected<value_type_t, traits>::value &&
444
        is_detected<difference_type_t, traits>::value &&
445
        is_detected<pointer_t, traits>::value &&
446
        is_detected<iterator_category_t, traits>::value &&
447
        is_detected<reference_t, traits>::value;
448
};
449
450
// source: https://stackoverflow.com/a/37193089/4116453
451
452
template <typename T, typename = void>
453
struct is_complete_type : std::false_type {};
454
455
template <typename T>
456
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
457
458
template <typename BasicJsonType, typename CompatibleObjectType,
459
          typename = void>
460
struct is_compatible_object_type_impl : std::false_type {};
461
462
template <typename BasicJsonType, typename CompatibleObjectType>
463
struct is_compatible_object_type_impl <
464
    BasicJsonType, CompatibleObjectType,
465
    enable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value and
466
    is_detected<key_type_t, CompatibleObjectType>::value >>
467
{
468
469
    using object_t = typename BasicJsonType::object_t;
470
471
    // macOS's is_constructible does not play well with nonesuch...
472
    static constexpr bool value =
473
        std::is_constructible<typename object_t::key_type,
474
        typename CompatibleObjectType::key_type>::value and
475
        std::is_constructible<typename object_t::mapped_type,
476
        typename CompatibleObjectType::mapped_type>::value;
477
};
478
479
template <typename BasicJsonType, typename CompatibleObjectType>
480
struct is_compatible_object_type
481
    : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
482
483
template <typename BasicJsonType, typename CompatibleStringType,
484
          typename = void>
485
struct is_compatible_string_type_impl : std::false_type {};
486
487
template <typename BasicJsonType, typename CompatibleStringType>
488
struct is_compatible_string_type_impl <
489
    BasicJsonType, CompatibleStringType,
490
    enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,
491
    value_type_t, CompatibleStringType>::value >>
492
{
493
    static constexpr auto value =
494
        std::is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
495
};
496
497
template <typename BasicJsonType, typename CompatibleStringType>
498
struct is_compatible_string_type
499
    : is_compatible_string_type_impl<BasicJsonType, CompatibleStringType> {};
500
501
template <typename BasicJsonType, typename CompatibleArrayType, typename = void>
502
struct is_compatible_array_type_impl : std::false_type {};
503
504
template <typename BasicJsonType, typename CompatibleArrayType>
505
struct is_compatible_array_type_impl <
506
    BasicJsonType, CompatibleArrayType,
507
    enable_if_t<is_detected<value_type_t, CompatibleArrayType>::value and
508
    is_detected<iterator_t, CompatibleArrayType>::value >>
509
{
510
    // This is needed because json_reverse_iterator has a ::iterator type...
511
    // Therefore it is detected as a CompatibleArrayType.
512
    // The real fix would be to have an Iterable concept.
513
    static constexpr bool value = not is_iterator_traits<std::iterator_traits<CompatibleArrayType>>::value;
514
};
515
516
template <typename BasicJsonType, typename CompatibleArrayType>
517
struct is_compatible_array_type
518
    : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
519
520
template <typename RealIntegerType, typename CompatibleNumberIntegerType,
521
          typename = void>
522
struct is_compatible_integer_type_impl : std::false_type {};
523
524
template <typename RealIntegerType, typename CompatibleNumberIntegerType>
525
struct is_compatible_integer_type_impl <
526
    RealIntegerType, CompatibleNumberIntegerType,
527
    enable_if_t<std::is_integral<RealIntegerType>::value and
528
    std::is_integral<CompatibleNumberIntegerType>::value and
529
    not std::is_same<bool, CompatibleNumberIntegerType>::value >>
530
{
531
    // is there an assert somewhere on overflows?
532
    using RealLimits = std::numeric_limits<RealIntegerType>;
533
    using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
534
535
    static constexpr auto value =
536
        std::is_constructible<RealIntegerType,
537
        CompatibleNumberIntegerType>::value and
538
        CompatibleLimits::is_integer and
539
        RealLimits::is_signed == CompatibleLimits::is_signed;
540
};
541
542
template <typename RealIntegerType, typename CompatibleNumberIntegerType>
543
struct is_compatible_integer_type
544
    : is_compatible_integer_type_impl<RealIntegerType,
545
      CompatibleNumberIntegerType> {};
546
547
// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
548
template<typename BasicJsonType, typename T>
549
struct has_from_json
550
{
551
    using serializer = typename BasicJsonType::template json_serializer<T, void>;
552
553
    static constexpr bool value =
554
        is_detected_exact<void, from_json_function, serializer,
555
        const BasicJsonType&, T&>::value;
556
};
557
558
// This trait checks if JSONSerializer<T>::from_json(json const&) exists
559
// this overload is used for non-default-constructible user-defined-types
560
template<typename BasicJsonType, typename T>
561
struct has_non_default_from_json
562
{
563
    using serializer = typename BasicJsonType::template json_serializer<T, void>;
564
565
    static constexpr bool value =
566
        is_detected_exact<T, from_json_function, serializer,
567
        const BasicJsonType&>::value;
568
};
569
570
// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
571
template<typename BasicJsonType, typename T>
572
struct has_to_json
573
{
574
    using serializer = typename BasicJsonType::template json_serializer<T, void>;
575
576
    static constexpr bool value =
577
        is_detected_exact<void, to_json_function, serializer, BasicJsonType&,
578
        T>::value;
579
};
580
581
template <typename BasicJsonType, typename CompatibleType, typename = void>
582
struct is_compatible_type_impl: std::false_type {};
583
584
template <typename BasicJsonType, typename CompatibleType>
585
struct is_compatible_type_impl <
586
    BasicJsonType, CompatibleType,
587
    enable_if_t<is_complete_type<CompatibleType>::value >>
588
{
589
    static constexpr bool value =
590
        has_to_json<BasicJsonType, CompatibleType>::value;
591
};
592
593
template <typename BasicJsonType, typename CompatibleType>
594
struct is_compatible_type
595
    : is_compatible_type_impl<BasicJsonType, CompatibleType> {};
596
}
597
}
598
599
// #include <nlohmann/detail/exceptions.hpp>
600
601
602
#include <exception> // exception
603
#include <stdexcept> // runtime_error
604
#include <string> // to_string
605
606
namespace nlohmann
607
{
608
namespace detail
609
{
610
////////////////
611
// exceptions //
612
////////////////
613
614
/*!
615
@brief general exception of the @ref basic_json class
616
617
This class is an extension of `std::exception` objects with a member @a id for
618
exception ids. It is used as the base class for all exceptions thrown by the
619
@ref basic_json class. This class can hence be used as "wildcard" to catch
620
exceptions.
621
622
Subclasses:
623
- @ref parse_error for exceptions indicating a parse error
624
- @ref invalid_iterator for exceptions indicating errors with iterators
625
- @ref type_error for exceptions indicating executing a member function with
626
                  a wrong type
627
- @ref out_of_range for exceptions indicating access out of the defined range
628
- @ref other_error for exceptions indicating other library errors
629
630
@internal
631
@note To have nothrow-copy-constructible exceptions, we internally use
632
      `std::runtime_error` which can cope with arbitrary-length error messages.
633
      Intermediate strings are built with static functions and then passed to
634
      the actual constructor.
635
@endinternal
636
637
@liveexample{The following code shows how arbitrary library exceptions can be
638
caught.,exception}
639
640
@since version 3.0.0
641
*/
642
class exception : public std::exception
643
{
644
  public:
645
    /// returns the explanatory string
646
    const char* what() const noexcept override
647
0
    {
648
0
        return m.what();
649
0
    }
650
651
    /// the id of the exception
652
    const int id;
653
654
  protected:
655
8
    exception(int id_, const char* what_arg) : id(id_), m(what_arg) {}
656
657
    static std::string name(const std::string& ename, int id_)
658
8
    {
659
8
        return "[json.exception." + ename + "." + std::to_string(id_) + "] ";
660
8
    }
661
662
  private:
663
    /// an exception object as storage for error messages
664
    std::runtime_error m;
665
};
666
667
/*!
668
@brief exception indicating a parse error
669
670
This exception is thrown by the library when a parse error occurs. Parse errors
671
can occur during the deserialization of JSON text, CBOR, MessagePack, as well
672
as when using JSON Patch.
673
674
Member @a byte holds the byte index of the last read character in the input
675
file.
676
677
Exceptions have ids 1xx.
678
679
name / id                      | example message | description
680
------------------------------ | --------------- | -------------------------
681
json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position.
682
json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point.
683
json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid.
684
json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects.
685
json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors.
686
json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`.
687
json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character.
688
json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences.
689
json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number.
690
json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read.
691
json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.
692
json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read.
693
694
@note For an input with n bytes, 1 is the index of the first character and n+1
695
      is the index of the terminating null byte or the end of file. This also
696
      holds true when reading a byte vector (CBOR or MessagePack).
697
698
@liveexample{The following code shows how a `parse_error` exception can be
699
caught.,parse_error}
700
701
@sa @ref exception for the base class of the library exceptions
702
@sa @ref invalid_iterator for exceptions indicating errors with iterators
703
@sa @ref type_error for exceptions indicating executing a member function with
704
                    a wrong type
705
@sa @ref out_of_range for exceptions indicating access out of the defined range
706
@sa @ref other_error for exceptions indicating other library errors
707
708
@since version 3.0.0
709
*/
710
class parse_error : public exception
711
{
712
  public:
713
    /*!
714
    @brief create a parse error exception
715
    @param[in] id_       the id of the exception
716
    @param[in] byte_     the byte index where the error occurred (or 0 if the
717
                         position cannot be determined)
718
    @param[in] what_arg  the explanatory string
719
    @return parse_error object
720
    */
721
    static parse_error create(int id_, std::size_t byte_, const std::string& what_arg)
722
4
    {
723
4
        std::string w = exception::name("parse_error", id_) + "parse error" +
724
4
                        (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") +
725
4
                        ": " + what_arg;
726
4
        return parse_error(id_, byte_, w.c_str());
727
4
    }
728
729
    /*!
730
    @brief byte index of the parse error
731
732
    The byte index of the last read character in the input file.
733
734
    @note For an input with n bytes, 1 is the index of the first character and
735
          n+1 is the index of the terminating null byte or the end of file.
736
          This also holds true when reading a byte vector (CBOR or MessagePack).
737
    */
738
    const std::size_t byte;
739
740
  private:
741
    parse_error(int id_, std::size_t byte_, const char* what_arg)
742
4
        : exception(id_, what_arg), byte(byte_) {}
743
};
744
745
/*!
746
@brief exception indicating errors with iterators
747
748
This exception is thrown if iterators passed to a library function do not match
749
the expected semantics.
750
751
Exceptions have ids 2xx.
752
753
name / id                           | example message | description
754
----------------------------------- | --------------- | -------------------------
755
json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.
756
json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion.
757
json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from.
758
json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid.
759
json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid.
760
json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range.
761
json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key.
762
json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.
763
json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.
764
json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.
765
json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to.
766
json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container.
767
json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered.
768
json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin().
769
770
@liveexample{The following code shows how an `invalid_iterator` exception can be
771
caught.,invalid_iterator}
772
773
@sa @ref exception for the base class of the library exceptions
774
@sa @ref parse_error for exceptions indicating a parse error
775
@sa @ref type_error for exceptions indicating executing a member function with
776
                    a wrong type
777
@sa @ref out_of_range for exceptions indicating access out of the defined range
778
@sa @ref other_error for exceptions indicating other library errors
779
780
@since version 3.0.0
781
*/
782
class invalid_iterator : public exception
783
{
784
  public:
785
    static invalid_iterator create(int id_, const std::string& what_arg)
786
0
    {
787
0
        std::string w = exception::name("invalid_iterator", id_) + what_arg;
788
0
        return invalid_iterator(id_, w.c_str());
789
0
    }
790
791
  private:
792
    invalid_iterator(int id_, const char* what_arg)
793
0
        : exception(id_, what_arg) {}
794
};
795
796
/*!
797
@brief exception indicating executing a member function with a wrong type
798
799
This exception is thrown in case of a type error; that is, a library function is
800
executed on a JSON value whose type does not match the expected semantics.
801
802
Exceptions have ids 3xx.
803
804
name / id                     | example message | description
805
----------------------------- | --------------- | -------------------------
806
json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead.
807
json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types.
808
json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&.
809
json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types.
810
json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types.
811
json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types.
812
json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types.
813
json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types.
814
json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types.
815
json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types.
816
json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types.
817
json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types.
818
json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined.
819
json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers.
820
json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive.
821
json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. |
822
823
@liveexample{The following code shows how a `type_error` exception can be
824
caught.,type_error}
825
826
@sa @ref exception for the base class of the library exceptions
827
@sa @ref parse_error for exceptions indicating a parse error
828
@sa @ref invalid_iterator for exceptions indicating errors with iterators
829
@sa @ref out_of_range for exceptions indicating access out of the defined range
830
@sa @ref other_error for exceptions indicating other library errors
831
832
@since version 3.0.0
833
*/
834
class type_error : public exception
835
{
836
  public:
837
    static type_error create(int id_, const std::string& what_arg)
838
0
    {
839
0
        std::string w = exception::name("type_error", id_) + what_arg;
840
0
        return type_error(id_, w.c_str());
841
0
    }
842
843
  private:
844
0
    type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
845
};
846
847
/*!
848
@brief exception indicating access out of the defined range
849
850
This exception is thrown in case a library function is called on an input
851
parameter that exceeds the expected range, for instance in case of array
852
indices or nonexisting object keys.
853
854
Exceptions have ids 4xx.
855
856
name / id                       | example message | description
857
------------------------------- | --------------- | -------------------------
858
json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1.
859
json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it.
860
json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object.
861
json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved.
862
json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value.
863
json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF.
864
json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON only supports integers numbers up to 9223372036854775807. |
865
json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. |
866
867
@liveexample{The following code shows how an `out_of_range` exception can be
868
caught.,out_of_range}
869
870
@sa @ref exception for the base class of the library exceptions
871
@sa @ref parse_error for exceptions indicating a parse error
872
@sa @ref invalid_iterator for exceptions indicating errors with iterators
873
@sa @ref type_error for exceptions indicating executing a member function with
874
                    a wrong type
875
@sa @ref other_error for exceptions indicating other library errors
876
877
@since version 3.0.0
878
*/
879
class out_of_range : public exception
880
{
881
  public:
882
    static out_of_range create(int id_, const std::string& what_arg)
883
4
    {
884
4
        std::string w = exception::name("out_of_range", id_) + what_arg;
885
4
        return out_of_range(id_, w.c_str());
886
4
    }
887
888
  private:
889
4
    out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
890
};
891
892
/*!
893
@brief exception indicating other library errors
894
895
This exception is thrown in case of errors that cannot be classified with the
896
other exception types.
897
898
Exceptions have ids 5xx.
899
900
name / id                      | example message | description
901
------------------------------ | --------------- | -------------------------
902
json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.
903
904
@sa @ref exception for the base class of the library exceptions
905
@sa @ref parse_error for exceptions indicating a parse error
906
@sa @ref invalid_iterator for exceptions indicating errors with iterators
907
@sa @ref type_error for exceptions indicating executing a member function with
908
                    a wrong type
909
@sa @ref out_of_range for exceptions indicating access out of the defined range
910
911
@liveexample{The following code shows how an `other_error` exception can be
912
caught.,other_error}
913
914
@since version 3.0.0
915
*/
916
class other_error : public exception
917
{
918
  public:
919
    static other_error create(int id_, const std::string& what_arg)
920
0
    {
921
0
        std::string w = exception::name("other_error", id_) + what_arg;
922
0
        return other_error(id_, w.c_str());
923
0
    }
924
925
  private:
926
0
    other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
927
};
928
}
929
}
930
931
// #include <nlohmann/detail/value_t.hpp>
932
933
934
#include <array> // array
935
#include <ciso646> // and
936
#include <cstddef> // size_t
937
#include <cstdint> // uint8_t
938
939
namespace nlohmann
940
{
941
namespace detail
942
{
943
///////////////////////////
944
// JSON type enumeration //
945
///////////////////////////
946
947
/*!
948
@brief the JSON type enumeration
949
950
This enumeration collects the different JSON types. It is internally used to
951
distinguish the stored values, and the functions @ref basic_json::is_null(),
952
@ref basic_json::is_object(), @ref basic_json::is_array(),
953
@ref basic_json::is_string(), @ref basic_json::is_boolean(),
954
@ref basic_json::is_number() (with @ref basic_json::is_number_integer(),
955
@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),
956
@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and
957
@ref basic_json::is_structured() rely on it.
958
959
@note There are three enumeration entries (number_integer, number_unsigned, and
960
number_float), because the library distinguishes these three types for numbers:
961
@ref basic_json::number_unsigned_t is used for unsigned integers,
962
@ref basic_json::number_integer_t is used for signed integers, and
963
@ref basic_json::number_float_t is used for floating-point numbers or to
964
approximate integers which do not fit in the limits of their respective type.
965
966
@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON
967
value with the default value for a given type
968
969
@since version 1.0.0
970
*/
971
enum class value_t : std::uint8_t
972
{
973
    null,             ///< null value
974
    object,           ///< object (unordered set of name/value pairs)
975
    array,            ///< array (ordered collection of values)
976
    string,           ///< string value
977
    boolean,          ///< boolean value
978
    number_integer,   ///< number value (signed integer)
979
    number_unsigned,  ///< number value (unsigned integer)
980
    number_float,     ///< number value (floating-point)
981
    discarded         ///< discarded by the the parser callback function
982
};
983
984
/*!
985
@brief comparison operator for JSON types
986
987
Returns an ordering that is similar to Python:
988
- order: null < boolean < number < object < array < string
989
- furthermore, each type is not smaller than itself
990
- discarded values are not comparable
991
992
@since version 1.0.0
993
*/
994
inline bool operator<(const value_t lhs, const value_t rhs) noexcept
995
0
{
996
0
    static constexpr std::array<std::uint8_t, 8> order = {{
997
0
            0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,
998
0
            1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */
999
0
        }
1000
0
    };
1001
0
1002
0
    const auto l_index = static_cast<std::size_t>(lhs);
1003
0
    const auto r_index = static_cast<std::size_t>(rhs);
1004
0
    return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index];
1005
0
}
1006
}
1007
}
1008
1009
// #include <nlohmann/detail/conversions/from_json.hpp>
1010
1011
1012
#include <algorithm> // transform
1013
#include <array> // array
1014
#include <ciso646> // and, not
1015
#include <forward_list> // forward_list
1016
#include <iterator> // inserter, front_inserter, end
1017
#include <map> // map
1018
#include <string> // string
1019
#include <tuple> // tuple, make_tuple
1020
#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
1021
#include <unordered_map> // unordered_map
1022
#include <utility> // pair, declval
1023
#include <valarray> // valarray
1024
1025
// #include <nlohmann/detail/exceptions.hpp>
1026
1027
// #include <nlohmann/detail/macro_scope.hpp>
1028
1029
// #include <nlohmann/detail/meta/cpp_future.hpp>
1030
1031
// #include <nlohmann/detail/meta/type_traits.hpp>
1032
1033
// #include <nlohmann/detail/value_t.hpp>
1034
1035
1036
namespace nlohmann
1037
{
1038
namespace detail
1039
{
1040
template<typename BasicJsonType>
1041
void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
1042
{
1043
    if (JSON_UNLIKELY(not j.is_null()))
1044
    {
1045
        JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name())));
1046
    }
1047
    n = nullptr;
1048
}
1049
1050
// overloads for basic_json template parameters
1051
template<typename BasicJsonType, typename ArithmeticType,
1052
         enable_if_t<std::is_arithmetic<ArithmeticType>::value and
1053
                     not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
1054
                     int> = 0>
1055
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
1056
592
{
1057
592
    switch (static_cast<value_t>(j))
1058
592
    {
1059
592
        case value_t::number_unsigned:
1060
0
        {
1061
0
            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
1062
0
            break;
1063
592
        }
1064
592
        case value_t::number_integer:
1065
0
        {
1066
0
            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
1067
0
            break;
1068
592
        }
1069
592
        case value_t::number_float:
1070
592
        {
1071
592
            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
1072
592
            break;
1073
592
        }
1074
592
1075
592
        default:
1076
0
            JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name())));
1077
592
    }
1078
592
}
1079
1080
template<typename BasicJsonType>
1081
void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
1082
8
{
1083
8
    if (JSON_UNLIKELY(not j.is_boolean()))
1084
8
    {
1085
0
        JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name())));
1086
0
    }
1087
8
    b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
1088
8
}
1089
1090
template<typename BasicJsonType>
1091
void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
1092
46.5k
{
1093
46.5k
    if (JSON_UNLIKELY(not j.is_string()))
1094
46.5k
    {
1095
0
        JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
1096
0
    }
1097
46.5k
    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
1098
46.5k
}
1099
1100
template <
1101
    typename BasicJsonType, typename CompatibleStringType,
1102
    enable_if_t <
1103
        is_compatible_string_type<BasicJsonType, CompatibleStringType>::value and
1104
        not std::is_same<typename BasicJsonType::string_t,
1105
                         CompatibleStringType>::value,
1106
        int > = 0 >
1107
void from_json(const BasicJsonType& j, CompatibleStringType& s)
1108
{
1109
    if (JSON_UNLIKELY(not j.is_string()))
1110
    {
1111
        JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
1112
    }
1113
1114
    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
1115
}
1116
1117
template<typename BasicJsonType>
1118
void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
1119
592
{
1120
592
    get_arithmetic_value(j, val);
1121
592
}
1122
1123
template<typename BasicJsonType>
1124
void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)
1125
{
1126
    get_arithmetic_value(j, val);
1127
}
1128
1129
template<typename BasicJsonType>
1130
void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
1131
{
1132
    get_arithmetic_value(j, val);
1133
}
1134
1135
template<typename BasicJsonType, typename EnumType,
1136
         enable_if_t<std::is_enum<EnumType>::value, int> = 0>
1137
void from_json(const BasicJsonType& j, EnumType& e)
1138
{
1139
    typename std::underlying_type<EnumType>::type val;
1140
    get_arithmetic_value(j, val);
1141
    e = static_cast<EnumType>(val);
1142
}
1143
1144
// forward_list doesn't have an insert method
1145
template<typename BasicJsonType, typename T, typename Allocator,
1146
         enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>
1147
void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
1148
{
1149
    if (JSON_UNLIKELY(not j.is_array()))
1150
    {
1151
        JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
1152
    }
1153
    std::transform(j.rbegin(), j.rend(),
1154
                   std::front_inserter(l), [](const BasicJsonType & i)
1155
    {
1156
        return i.template get<T>();
1157
    });
1158
}
1159
1160
// valarray doesn't have an insert method
1161
template<typename BasicJsonType, typename T,
1162
         enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>
1163
void from_json(const BasicJsonType& j, std::valarray<T>& l)
1164
{
1165
    if (JSON_UNLIKELY(not j.is_array()))
1166
    {
1167
        JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
1168
    }
1169
    l.resize(j.size());
1170
    std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l));
1171
}
1172
1173
template<typename BasicJsonType>
1174
void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
1175
{
1176
    arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
1177
}
1178
1179
template <typename BasicJsonType, typename T, std::size_t N>
1180
auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
1181
                          priority_tag<2> /*unused*/)
1182
-> decltype(j.template get<T>(), void())
1183
{
1184
    for (std::size_t i = 0; i < N; ++i)
1185
    {
1186
        arr[i] = j.at(i).template get<T>();
1187
    }
1188
}
1189
1190
template<typename BasicJsonType, typename CompatibleArrayType>
1191
auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/)
1192
-> decltype(
1193
    arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
1194
    j.template get<typename CompatibleArrayType::value_type>(),
1195
    void())
1196
{
1197
    using std::end;
1198
1199
    arr.reserve(j.size());
1200
    std::transform(j.begin(), j.end(),
1201
                   std::inserter(arr, end(arr)), [](const BasicJsonType & i)
1202
    {
1203
        // get<BasicJsonType>() returns *this, this won't call a from_json
1204
        // method when value_type is BasicJsonType
1205
        return i.template get<typename CompatibleArrayType::value_type>();
1206
    });
1207
}
1208
1209
template <typename BasicJsonType, typename CompatibleArrayType>
1210
void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr,
1211
                          priority_tag<0> /*unused*/)
1212
{
1213
    using std::end;
1214
1215
    std::transform(
1216
        j.begin(), j.end(), std::inserter(arr, end(arr)),
1217
        [](const BasicJsonType & i)
1218
    {
1219
        // get<BasicJsonType>() returns *this, this won't call a from_json
1220
        // method when value_type is BasicJsonType
1221
        return i.template get<typename CompatibleArrayType::value_type>();
1222
    });
1223
}
1224
1225
template <typename BasicJsonType, typename CompatibleArrayType,
1226
          enable_if_t <
1227
              is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
1228
              not is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value and
1229
              not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and
1230
              not is_basic_json<CompatibleArrayType>::value,
1231
              int > = 0 >
1232
1233
auto from_json(const BasicJsonType& j, CompatibleArrayType& arr)
1234
-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
1235
j.template get<typename CompatibleArrayType::value_type>(),
1236
void())
1237
{
1238
    if (JSON_UNLIKELY(not j.is_array()))
1239
    {
1240
        JSON_THROW(type_error::create(302, "type must be array, but is " +
1241
                                      std::string(j.type_name())));
1242
    }
1243
1244
    from_json_array_impl(j, arr, priority_tag<3> {});
1245
}
1246
1247
template<typename BasicJsonType, typename CompatibleObjectType,
1248
         enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value, int> = 0>
1249
void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
1250
{
1251
    if (JSON_UNLIKELY(not j.is_object()))
1252
    {
1253
        JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name())));
1254
    }
1255
1256
    auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
1257
    using value_type = typename CompatibleObjectType::value_type;
1258
    std::transform(
1259
        inner_object->begin(), inner_object->end(),
1260
        std::inserter(obj, obj.begin()),
1261
        [](typename BasicJsonType::object_t::value_type const & p)
1262
    {
1263
        return value_type(p.first, p.second.template get<typename CompatibleObjectType::mapped_type>());
1264
    });
1265
}
1266
1267
// overload for arithmetic types, not chosen for basic_json template arguments
1268
// (BooleanType, etc..); note: Is it really necessary to provide explicit
1269
// overloads for boolean_t etc. in case of a custom BooleanType which is not
1270
// an arithmetic type?
1271
template<typename BasicJsonType, typename ArithmeticType,
1272
         enable_if_t <
1273
             std::is_arithmetic<ArithmeticType>::value and
1274
             not std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value and
1275
             not std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value and
1276
             not std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value and
1277
             not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
1278
             int> = 0>
1279
void from_json(const BasicJsonType& j, ArithmeticType& val)
1280
608
{
1281
608
    switch (static_cast<value_t>(j))
1282
608
    {
1283
608
        case value_t::number_unsigned:
1284
608
        {
1285
608
            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
1286
608
            break;
1287
608
        }
1288
608
        case value_t::number_integer:
1289
0
        {
1290
0
            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
1291
0
            break;
1292
608
        }
1293
608
        case value_t::number_float:
1294
0
        {
1295
0
            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
1296
0
            break;
1297
608
        }
1298
608
        case value_t::boolean:
1299
0
        {
1300
0
            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
1301
0
            break;
1302
608
        }
1303
608
1304
608
        default:
1305
0
            JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name())));
1306
608
    }
1307
608
}
1308
1309
template<typename BasicJsonType, typename A1, typename A2>
1310
void from_json(const BasicJsonType& j, std::pair<A1, A2>& p)
1311
{
1312
    p = {j.at(0).template get<A1>(), j.at(1).template get<A2>()};
1313
}
1314
1315
template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
1316
void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx...>)
1317
{
1318
    t = std::make_tuple(j.at(Idx).template get<typename std::tuple_element<Idx, Tuple>::type>()...);
1319
}
1320
1321
template<typename BasicJsonType, typename... Args>
1322
void from_json(const BasicJsonType& j, std::tuple<Args...>& t)
1323
{
1324
    from_json_tuple_impl(j, t, index_sequence_for<Args...> {});
1325
}
1326
1327
template <typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
1328
          typename = enable_if_t<not std::is_constructible<
1329
                                     typename BasicJsonType::string_t, Key>::value>>
1330
void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
1331
{
1332
    if (JSON_UNLIKELY(not j.is_array()))
1333
    {
1334
        JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
1335
    }
1336
    for (const auto& p : j)
1337
    {
1338
        if (JSON_UNLIKELY(not p.is_array()))
1339
        {
1340
            JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
1341
        }
1342
        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
1343
    }
1344
}
1345
1346
template <typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
1347
          typename = enable_if_t<not std::is_constructible<
1348
                                     typename BasicJsonType::string_t, Key>::value>>
1349
void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
1350
{
1351
    if (JSON_UNLIKELY(not j.is_array()))
1352
    {
1353
        JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
1354
    }
1355
    for (const auto& p : j)
1356
    {
1357
        if (JSON_UNLIKELY(not p.is_array()))
1358
        {
1359
            JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
1360
        }
1361
        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
1362
    }
1363
}
1364
1365
struct from_json_fn
1366
{
1367
    template<typename BasicJsonType, typename T>
1368
    auto operator()(const BasicJsonType& j, T& val) const
1369
    noexcept(noexcept(from_json(j, val)))
1370
    -> decltype(from_json(j, val), void())
1371
47.7k
    {
1372
47.7k
        return from_json(j, val);
1373
47.7k
    }
_ZNK8nlohmann6detail12from_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEbEEDTcmcl9from_jsonfp_fp0_Ecvv_EERKT_RT0_
Line
Count
Source
1371
8
    {
1372
8
        return from_json(j, val);
1373
8
    }
_ZNK8nlohmann6detail12from_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEESB_EEDTcmcl9from_jsonfp_fp0_Ecvv_EERKT_RT0_
Line
Count
Source
1371
46.5k
    {
1372
46.5k
        return from_json(j, val);
1373
46.5k
    }
_ZNK8nlohmann6detail12from_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEiEEDTcmcl9from_jsonfp_fp0_Ecvv_EERKT_RT0_
Line
Count
Source
1371
608
    {
1372
608
        return from_json(j, val);
1373
608
    }
_ZNK8nlohmann6detail12from_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEdEEDTcmcl9from_jsonfp_fp0_Ecvv_EERKT_RT0_
Line
Count
Source
1371
592
    {
1372
592
        return from_json(j, val);
1373
592
    }
1374
};
1375
}
1376
1377
/// namespace to hold default `from_json` function
1378
/// to see why this is required:
1379
/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
1380
namespace
1381
{
1382
constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value;
1383
}
1384
}
1385
1386
// #include <nlohmann/detail/conversions/to_json.hpp>
1387
1388
1389
#include <ciso646> // or, and, not
1390
#include <iterator> // begin, end
1391
#include <tuple> // tuple, get
1392
#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type
1393
#include <utility> // move, forward, declval, pair
1394
#include <valarray> // valarray
1395
#include <vector> // vector
1396
1397
// #include <nlohmann/detail/meta/cpp_future.hpp>
1398
1399
// #include <nlohmann/detail/meta/type_traits.hpp>
1400
1401
// #include <nlohmann/detail/value_t.hpp>
1402
1403
// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
1404
1405
1406
#include <cstddef> // size_t
1407
#include <string> // string, to_string
1408
#include <iterator> // input_iterator_tag
1409
1410
// #include <nlohmann/detail/value_t.hpp>
1411
1412
1413
namespace nlohmann
1414
{
1415
namespace detail
1416
{
1417
/// proxy class for the items() function
1418
template<typename IteratorType> class iteration_proxy
1419
{
1420
  private:
1421
    /// helper class for iteration
1422
    class iteration_proxy_internal
1423
    {
1424
      public:
1425
        using difference_type = std::ptrdiff_t;
1426
        using value_type = iteration_proxy_internal;
1427
        using pointer = iteration_proxy_internal*;
1428
        using reference = iteration_proxy_internal&;
1429
        using iterator_category = std::input_iterator_tag;
1430
1431
      private:
1432
        /// the iterator
1433
        IteratorType anchor;
1434
        /// an index for arrays (used to create key names)
1435
        std::size_t array_index = 0;
1436
        /// last stringified array index
1437
        mutable std::size_t array_index_last = 0;
1438
        /// a string representation of the array index
1439
        mutable std::string array_index_str = "0";
1440
        /// an empty string (to return a reference for primitive values)
1441
        const std::string empty_str = "";
1442
1443
      public:
1444
        explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {}
1445
1446
        iteration_proxy_internal(const iteration_proxy_internal&) = default;
1447
        iteration_proxy_internal& operator=(const iteration_proxy_internal&) = default;
1448
1449
        /// dereference operator (needed for range-based for)
1450
        iteration_proxy_internal& operator*()
1451
        {
1452
            return *this;
1453
        }
1454
1455
        /// increment operator (needed for range-based for)
1456
        iteration_proxy_internal& operator++()
1457
        {
1458
            ++anchor;
1459
            ++array_index;
1460
1461
            return *this;
1462
        }
1463
1464
        /// equality operator (needed for InputIterator)
1465
        bool operator==(const iteration_proxy_internal& o) const noexcept
1466
        {
1467
            return anchor == o.anchor;
1468
        }
1469
1470
        /// inequality operator (needed for range-based for)
1471
        bool operator!=(const iteration_proxy_internal& o) const noexcept
1472
        {
1473
            return anchor != o.anchor;
1474
        }
1475
1476
        /// return key of the iterator
1477
        const std::string& key() const
1478
        {
1479
            assert(anchor.m_object != nullptr);
1480
1481
            switch (anchor.m_object->type())
1482
            {
1483
                // use integer array index as key
1484
                case value_t::array:
1485
                {
1486
                    if (array_index != array_index_last)
1487
                    {
1488
                        array_index_str = std::to_string(array_index);
1489
                        array_index_last = array_index;
1490
                    }
1491
                    return array_index_str;
1492
                }
1493
1494
                // use key from the object
1495
                case value_t::object:
1496
                    return anchor.key();
1497
1498
                // use an empty key for all primitive types
1499
                default:
1500
                    return empty_str;
1501
            }
1502
        }
1503
1504
        /// return value of the iterator
1505
        typename IteratorType::reference value() const
1506
        {
1507
            return anchor.value();
1508
        }
1509
    };
1510
1511
    /// the container to iterate
1512
    typename IteratorType::reference container;
1513
1514
  public:
1515
    /// construct iteration proxy from a container
1516
    explicit iteration_proxy(typename IteratorType::reference cont) noexcept
1517
        : container(cont) {}
1518
1519
    /// return iterator begin (needed for range-based for)
1520
    iteration_proxy_internal begin() noexcept
1521
    {
1522
        return iteration_proxy_internal(container.begin());
1523
    }
1524
1525
    /// return iterator end (needed for range-based for)
1526
    iteration_proxy_internal end() noexcept
1527
    {
1528
        return iteration_proxy_internal(container.end());
1529
    }
1530
};
1531
}
1532
}
1533
1534
1535
namespace nlohmann
1536
{
1537
namespace detail
1538
{
1539
//////////////////
1540
// constructors //
1541
//////////////////
1542
1543
template<value_t> struct external_constructor;
1544
1545
template<>
1546
struct external_constructor<value_t::boolean>
1547
{
1548
    template<typename BasicJsonType>
1549
    static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
1550
2.46k
    {
1551
2.46k
        j.m_type = value_t::boolean;
1552
2.46k
        j.m_value = b;
1553
2.46k
        j.assert_invariant();
1554
2.46k
    }
1555
};
1556
1557
template<>
1558
struct external_constructor<value_t::string>
1559
{
1560
    template<typename BasicJsonType>
1561
    static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
1562
255k
    {
1563
255k
        j.m_type = value_t::string;
1564
255k
        j.m_value = s;
1565
255k
        j.assert_invariant();
1566
255k
    }
1567
1568
    template<typename BasicJsonType>
1569
    static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
1570
1.76k
    {
1571
1.76k
        j.m_type = value_t::string;
1572
1.76k
        j.m_value = std::move(s);
1573
1.76k
        j.assert_invariant();
1574
1.76k
    }
1575
1576
    template<typename BasicJsonType, typename CompatibleStringType,
1577
             enable_if_t<not std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
1578
                         int> = 0>
1579
    static void construct(BasicJsonType& j, const CompatibleStringType& str)
1580
856
    {
1581
856
        j.m_type = value_t::string;
1582
856
        j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
1583
856
        j.assert_invariant();
1584
856
    }
_ZN8nlohmann6detail20external_constructorILNS0_7value_tE3EE9constructINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEA474_cLi0EEEvRT_RKT0_
Line
Count
Source
1580
812
    {
1581
812
        j.m_type = value_t::string;
1582
812
        j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
1583
812
        j.assert_invariant();
1584
812
    }
_ZN8nlohmann6detail20external_constructorILNS0_7value_tE3EE9constructINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEPKcLi0EEEvRT_RKT0_
Line
Count
Source
1580
40
    {
1581
40
        j.m_type = value_t::string;
1582
40
        j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
1583
40
        j.assert_invariant();
1584
40
    }
_ZN8nlohmann6detail20external_constructorILNS0_7value_tE3EE9constructINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEA6_cLi0EEEvRT_RKT0_
Line
Count
Source
1580
4
    {
1581
4
        j.m_type = value_t::string;
1582
4
        j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
1583
4
        j.assert_invariant();
1584
4
    }
1585
};
1586
1587
template<>
1588
struct external_constructor<value_t::number_float>
1589
{
1590
    template<typename BasicJsonType>
1591
    static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
1592
234k
    {
1593
234k
        j.m_type = value_t::number_float;
1594
234k
        j.m_value = val;
1595
234k
        j.assert_invariant();
1596
234k
    }
1597
};
1598
1599
template<>
1600
struct external_constructor<value_t::number_unsigned>
1601
{
1602
    template<typename BasicJsonType>
1603
    static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
1604
314k
    {
1605
314k
        j.m_type = value_t::number_unsigned;
1606
314k
        j.m_value = val;
1607
314k
        j.assert_invariant();
1608
314k
    }
1609
};
1610
1611
template<>
1612
struct external_constructor<value_t::number_integer>
1613
{
1614
    template<typename BasicJsonType>
1615
    static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
1616
37.4k
    {
1617
37.4k
        j.m_type = value_t::number_integer;
1618
37.4k
        j.m_value = val;
1619
37.4k
        j.assert_invariant();
1620
37.4k
    }
1621
};
1622
1623
template<>
1624
struct external_constructor<value_t::array>
1625
{
1626
    template<typename BasicJsonType>
1627
    static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
1628
    {
1629
        j.m_type = value_t::array;
1630
        j.m_value = arr;
1631
        j.assert_invariant();
1632
    }
1633
1634
    template<typename BasicJsonType>
1635
    static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
1636
    {
1637
        j.m_type = value_t::array;
1638
        j.m_value = std::move(arr);
1639
        j.assert_invariant();
1640
    }
1641
1642
    template<typename BasicJsonType, typename CompatibleArrayType,
1643
             enable_if_t<not std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
1644
                         int> = 0>
1645
    static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
1646
    {
1647
        using std::begin;
1648
        using std::end;
1649
        j.m_type = value_t::array;
1650
        j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
1651
        j.assert_invariant();
1652
    }
1653
1654
    template<typename BasicJsonType>
1655
    static void construct(BasicJsonType& j, const std::vector<bool>& arr)
1656
    {
1657
        j.m_type = value_t::array;
1658
        j.m_value = value_t::array;
1659
        j.m_value.array->reserve(arr.size());
1660
        for (const bool x : arr)
1661
        {
1662
            j.m_value.array->push_back(x);
1663
        }
1664
        j.assert_invariant();
1665
    }
1666
1667
    template<typename BasicJsonType, typename T,
1668
             enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
1669
    static void construct(BasicJsonType& j, const std::valarray<T>& arr)
1670
    {
1671
        j.m_type = value_t::array;
1672
        j.m_value = value_t::array;
1673
        j.m_value.array->resize(arr.size());
1674
        std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());
1675
        j.assert_invariant();
1676
    }
1677
};
1678
1679
template<>
1680
struct external_constructor<value_t::object>
1681
{
1682
    template<typename BasicJsonType>
1683
    static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
1684
    {
1685
        j.m_type = value_t::object;
1686
        j.m_value = obj;
1687
        j.assert_invariant();
1688
    }
1689
1690
    template<typename BasicJsonType>
1691
    static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
1692
    {
1693
        j.m_type = value_t::object;
1694
        j.m_value = std::move(obj);
1695
        j.assert_invariant();
1696
    }
1697
1698
    template<typename BasicJsonType, typename CompatibleObjectType,
1699
             enable_if_t<not std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int> = 0>
1700
    static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
1701
    {
1702
        using std::begin;
1703
        using std::end;
1704
1705
        j.m_type = value_t::object;
1706
        j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
1707
        j.assert_invariant();
1708
    }
1709
};
1710
1711
/////////////
1712
// to_json //
1713
/////////////
1714
1715
template<typename BasicJsonType, typename T,
1716
         enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>
1717
void to_json(BasicJsonType& j, T b) noexcept
1718
2.46k
{
1719
2.46k
    external_constructor<value_t::boolean>::construct(j, b);
1720
2.46k
}
1721
1722
template<typename BasicJsonType, typename CompatibleString,
1723
         enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>
1724
void to_json(BasicJsonType& j, const CompatibleString& s)
1725
256k
{
1726
256k
    external_constructor<value_t::string>::construct(j, s);
1727
256k
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEESA_Li0EEEvRT_RKT0_
Line
Count
Source
1725
255k
{
1726
255k
    external_constructor<value_t::string>::construct(j, s);
1727
255k
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEA474_cLi0EEEvRT_RKT0_
Line
Count
Source
1725
812
{
1726
812
    external_constructor<value_t::string>::construct(j, s);
1727
812
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEPKcLi0EEEvRT_RKT0_
Line
Count
Source
1725
40
{
1726
40
    external_constructor<value_t::string>::construct(j, s);
1727
40
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEA6_cLi0EEEvRT_RKT0_
Line
Count
Source
1725
4
{
1726
4
    external_constructor<value_t::string>::construct(j, s);
1727
4
}
1728
1729
template<typename BasicJsonType>
1730
void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)
1731
1.76k
{
1732
1.76k
    external_constructor<value_t::string>::construct(j, std::move(s));
1733
1.76k
}
1734
1735
template<typename BasicJsonType, typename FloatType,
1736
         enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
1737
void to_json(BasicJsonType& j, FloatType val) noexcept
1738
234k
{
1739
234k
    external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));
1740
234k
}
1741
1742
template<typename BasicJsonType, typename CompatibleNumberUnsignedType,
1743
         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>
1744
void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept
1745
314k
{
1746
314k
    external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
1747
314k
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEmLi0EEEvRT_T0_
Line
Count
Source
1745
314k
{
1746
314k
    external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
1747
314k
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEjLi0EEEvRT_T0_
Line
Count
Source
1745
588
{
1746
588
    external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
1747
588
}
1748
1749
template<typename BasicJsonType, typename CompatibleNumberIntegerType,
1750
         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>
1751
void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
1752
37.4k
{
1753
37.4k
    external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
1754
37.4k
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEElLi0EEEvRT_T0_
Line
Count
Source
1752
37.4k
{
1753
37.4k
    external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
1754
37.4k
}
_ZN8nlohmann6detail7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEiLi0EEEvRT_T0_
Line
Count
Source
1752
4
{
1753
4
    external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
1754
4
}
1755
1756
template<typename BasicJsonType, typename EnumType,
1757
         enable_if_t<std::is_enum<EnumType>::value, int> = 0>
1758
void to_json(BasicJsonType& j, EnumType e) noexcept
1759
{
1760
    using underlying_type = typename std::underlying_type<EnumType>::type;
1761
    external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));
1762
}
1763
1764
template<typename BasicJsonType>
1765
void to_json(BasicJsonType& j, const std::vector<bool>& e)
1766
{
1767
    external_constructor<value_t::array>::construct(j, e);
1768
}
1769
1770
template <typename BasicJsonType, typename CompatibleArrayType,
1771
          enable_if_t<is_compatible_array_type<BasicJsonType,
1772
                      CompatibleArrayType>::value and
1773
                      not is_compatible_object_type<
1774
                          BasicJsonType, CompatibleArrayType>::value and
1775
                      not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and
1776
                      not is_basic_json<CompatibleArrayType>::value,
1777
                      int> = 0>
1778
void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
1779
{
1780
    external_constructor<value_t::array>::construct(j, arr);
1781
}
1782
1783
template<typename BasicJsonType, typename T,
1784
         enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
1785
void to_json(BasicJsonType& j, const std::valarray<T>& arr)
1786
{
1787
    external_constructor<value_t::array>::construct(j, std::move(arr));
1788
}
1789
1790
template<typename BasicJsonType>
1791
void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
1792
{
1793
    external_constructor<value_t::array>::construct(j, std::move(arr));
1794
}
1795
1796
template<typename BasicJsonType, typename CompatibleObjectType,
1797
         enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and not is_basic_json<CompatibleObjectType>::value, int> = 0>
1798
void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
1799
{
1800
    external_constructor<value_t::object>::construct(j, obj);
1801
}
1802
1803
template<typename BasicJsonType>
1804
void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
1805
{
1806
    external_constructor<value_t::object>::construct(j, std::move(obj));
1807
}
1808
1809
template <
1810
    typename BasicJsonType, typename T, std::size_t N,
1811
    enable_if_t<not std::is_constructible<typename BasicJsonType::string_t,
1812
                const T (&)[N]>::value,
1813
                int> = 0 >
1814
void to_json(BasicJsonType& j, const T (&arr)[N])
1815
{
1816
    external_constructor<value_t::array>::construct(j, arr);
1817
}
1818
1819
template<typename BasicJsonType, typename... Args>
1820
void to_json(BasicJsonType& j, const std::pair<Args...>& p)
1821
{
1822
    j = {p.first, p.second};
1823
}
1824
1825
// for https://github.com/nlohmann/json/pull/1134
1826
template<typename BasicJsonType, typename T,
1827
         enable_if_t<std::is_same<T, typename iteration_proxy<typename BasicJsonType::iterator>::iteration_proxy_internal>::value, int> = 0>
1828
void to_json(BasicJsonType& j, T b) noexcept
1829
{
1830
    j = {{b.key(), b.value()}};
1831
}
1832
1833
template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
1834
void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...>)
1835
{
1836
    j = {std::get<Idx>(t)...};
1837
}
1838
1839
template<typename BasicJsonType, typename... Args>
1840
void to_json(BasicJsonType& j, const std::tuple<Args...>& t)
1841
{
1842
    to_json_tuple_impl(j, t, index_sequence_for<Args...> {});
1843
}
1844
1845
struct to_json_fn
1846
{
1847
    template<typename BasicJsonType, typename T>
1848
    auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
1849
    -> decltype(to_json(j, std::forward<T>(val)), void())
1850
847k
    {
1851
847k
        return to_json(j, std::forward<T>(val));
1852
847k
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERSB_EEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
Line
Count
Source
1850
255k
    {
1851
255k
        return to_json(j, std::forward<T>(val));
1852
255k
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERdEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
Line
Count
Source
1850
234k
    {
1851
234k
        return to_json(j, std::forward<T>(val));
1852
234k
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERbEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
Line
Count
Source
1850
2.45k
    {
1851
2.45k
        return to_json(j, std::forward<T>(val));
1852
2.45k
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERlEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
Line
Count
Source
1850
37.4k
    {
1851
37.4k
        return to_json(j, std::forward<T>(val));
1852
37.4k
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERmEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
Line
Count
Source
1850
314k
    {
1851
314k
        return to_json(j, std::forward<T>(val));
1852
314k
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERA474_KcEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSH_
Line
Count
Source
1850
812
    {
1851
812
        return to_json(j, std::forward<T>(val));
1852
812
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEESB_EEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
Line
Count
Source
1850
1.76k
    {
1851
1.76k
        return to_json(j, std::forward<T>(val));
1852
1.76k
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEKSB_EEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
Line
Count
Source
1850
196
    {
1851
196
        return to_json(j, std::forward<T>(val));
1852
196
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERjEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
Line
Count
Source
1850
588
    {
1851
588
        return to_json(j, std::forward<T>(val));
1852
588
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERKPKcEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSI_
Line
Count
Source
1850
40
    {
1851
40
        return to_json(j, std::forward<T>(val));
1852
40
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEbEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
Line
Count
Source
1850
4
    {
1851
4
        return to_json(j, std::forward<T>(val));
1852
4
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEdEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
Line
Count
Source
1850
4
    {
1851
4
        return to_json(j, std::forward<T>(val));
1852
4
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEERA6_KcEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSH_
Line
Count
Source
1850
4
    {
1851
4
        return to_json(j, std::forward<T>(val));
1852
4
    }
_ZNK8nlohmann6detail10to_json_fnclINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEiEEDTcmcl7to_jsonfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
Line
Count
Source
1850
4
    {
1851
4
        return to_json(j, std::forward<T>(val));
1852
4
    }
1853
};
1854
}
1855
1856
/// namespace to hold default `to_json` function
1857
namespace
1858
{
1859
constexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value;
1860
}
1861
}
1862
1863
// #include <nlohmann/detail/input/input_adapters.hpp>
1864
1865
1866
#include <cassert> // assert
1867
#include <cstddef> // size_t
1868
#include <cstring> // strlen
1869
#include <istream> // istream
1870
#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
1871
#include <memory> // shared_ptr, make_shared, addressof
1872
#include <numeric> // accumulate
1873
#include <string> // string, char_traits
1874
#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
1875
#include <utility> // pair, declval
1876
1877
// #include <nlohmann/detail/macro_scope.hpp>
1878
1879
1880
namespace nlohmann
1881
{
1882
namespace detail
1883
{
1884
/// the supported input formats
1885
enum class input_format_t { json, cbor, msgpack, ubjson };
1886
1887
////////////////////
1888
// input adapters //
1889
////////////////////
1890
1891
/*!
1892
@brief abstract input adapter interface
1893
1894
Produces a stream of std::char_traits<char>::int_type characters from a
1895
std::istream, a buffer, or some other input type. Accepts the return of
1896
exactly one non-EOF character for future input. The int_type characters
1897
returned consist of all valid char values as positive values (typically
1898
unsigned char), plus an EOF value outside that range, specified by the value
1899
of the function std::char_traits<char>::eof(). This value is typically -1, but
1900
could be any arbitrary value which is not a valid char value.
1901
*/
1902
struct input_adapter_protocol
1903
{
1904
    /// get a character [0,255] or std::char_traits<char>::eof().
1905
    virtual std::char_traits<char>::int_type get_character() = 0;
1906
3.40k
    virtual ~input_adapter_protocol() = default;
1907
};
1908
1909
/// a type to simplify interfaces
1910
using input_adapter_t = std::shared_ptr<input_adapter_protocol>;
1911
1912
/*!
1913
Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at
1914
beginning of input. Does not support changing the underlying std::streambuf
1915
in mid-input. Maintains underlying std::istream and std::streambuf to support
1916
subsequent use of standard std::istream operations to process any input
1917
characters following those used in parsing the JSON input.  Clears the
1918
std::istream flags; any input errors (e.g., EOF) will be detected by the first
1919
subsequent call for input from the std::istream.
1920
*/
1921
class input_stream_adapter : public input_adapter_protocol
1922
{
1923
  public:
1924
    ~input_stream_adapter() override
1925
812
    {
1926
812
        // clear stream flags; we use underlying streambuf I/O, do not
1927
812
        // maintain ifstream flags
1928
812
        is.clear();
1929
812
    }
1930
1931
    explicit input_stream_adapter(std::istream& i)
1932
        : is(i), sb(*i.rdbuf())
1933
812
    {}
1934
1935
    // delete because of pointer members
1936
    input_stream_adapter(const input_stream_adapter&) = delete;
1937
    input_stream_adapter& operator=(input_stream_adapter&) = delete;
1938
1939
    // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to
1940
    // ensure that std::char_traits<char>::eof() and the character 0xFF do not
1941
    // end up as the same value, eg. 0xFFFFFFFF.
1942
    std::char_traits<char>::int_type get_character() override
1943
1.82M
    {
1944
1.82M
        return sb.sbumpc();
1945
1.82M
    }
1946
1947
  private:
1948
    /// the associated input stream
1949
    std::istream& is;
1950
    std::streambuf& sb;
1951
};
1952
1953
/// input adapter for buffer input
1954
class input_buffer_adapter : public input_adapter_protocol
1955
{
1956
  public:
1957
    input_buffer_adapter(const char* b, const std::size_t l)
1958
        : cursor(b), limit(b + l)
1959
2.59k
    {}
1960
1961
    // delete because of pointer members
1962
    input_buffer_adapter(const input_buffer_adapter&) = delete;
1963
    input_buffer_adapter& operator=(input_buffer_adapter&) = delete;
1964
1965
    std::char_traits<char>::int_type get_character() noexcept override
1966
16.8M
    {
1967
16.8M
        if (JSON_LIKELY(cursor < limit))
1968
16.8M
        {
1969
16.8M
            return std::char_traits<char>::to_int_type(*(cursor++));
1970
16.8M
        }
1971
160
1972
160
        return std::char_traits<char>::eof();
1973
160
    }
1974
1975
  private:
1976
    /// pointer to the current character
1977
    const char* cursor;
1978
    /// pointer past the last character
1979
    const char* const limit;
1980
};
1981
1982
template<typename WideStringType>
1983
class wide_string_input_adapter : public input_adapter_protocol
1984
{
1985
  public:
1986
    explicit wide_string_input_adapter(const WideStringType& w) : str(w) {}
1987
1988
    std::char_traits<char>::int_type get_character() noexcept override
1989
0
    {
1990
0
        // check if buffer needs to be filled
1991
0
        if (utf8_bytes_index == utf8_bytes_filled)
1992
0
        {
1993
0
            if (sizeof(typename WideStringType::value_type) == 2)
1994
0
            {
1995
0
                fill_buffer_utf16();
1996
0
            }
1997
0
            else
1998
0
            {
1999
0
                fill_buffer_utf32();
2000
0
            }
2001
0
2002
0
            assert(utf8_bytes_filled > 0);
2003
0
            assert(utf8_bytes_index == 0);
2004
0
        }
2005
0
2006
0
        // use buffer
2007
0
        assert(utf8_bytes_filled > 0);
2008
0
        assert(utf8_bytes_index < utf8_bytes_filled);
2009
0
        return utf8_bytes[utf8_bytes_index++];
2010
0
    }
Unexecuted instantiation: _ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIwSt11char_traitsIwESaIwEEEE13get_characterEv
Unexecuted instantiation: _ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIDsSt11char_traitsIDsESaIDsEEEE13get_characterEv
Unexecuted instantiation: _ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIDiSt11char_traitsIDiESaIDiEEEE13get_characterEv
2011
2012
  private:
2013
    void fill_buffer_utf16()
2014
0
    {
2015
0
        utf8_bytes_index = 0;
2016
0
2017
0
        if (current_wchar == str.size())
2018
0
        {
2019
0
            utf8_bytes[0] = std::char_traits<char>::eof();
2020
0
            utf8_bytes_filled = 1;
2021
0
        }
2022
0
        else
2023
0
        {
2024
0
            // get the current character
2025
0
            const int wc = static_cast<int>(str[current_wchar++]);
2026
0
2027
0
            // UTF-16 to UTF-8 encoding
2028
0
            if (wc < 0x80)
2029
0
            {
2030
0
                utf8_bytes[0] = wc;
2031
0
                utf8_bytes_filled = 1;
2032
0
            }
2033
0
            else if (wc <= 0x7FF)
2034
0
            {
2035
0
                utf8_bytes[0] = 0xC0 | ((wc >> 6));
2036
0
                utf8_bytes[1] = 0x80 | (wc & 0x3F);
2037
0
                utf8_bytes_filled = 2;
2038
0
            }
2039
0
            else if (0xD800 > wc or wc >= 0xE000)
2040
0
            {
2041
0
                utf8_bytes[0] = 0xE0 | ((wc >> 12));
2042
0
                utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
2043
0
                utf8_bytes[2] = 0x80 | (wc & 0x3F);
2044
0
                utf8_bytes_filled = 3;
2045
0
            }
2046
0
            else
2047
0
            {
2048
0
                if (current_wchar < str.size())
2049
0
                {
2050
0
                    const int wc2 = static_cast<int>(str[current_wchar++]);
2051
0
                    const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF));
2052
0
                    utf8_bytes[0] = 0xf0 | (charcode >> 18);
2053
0
                    utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F);
2054
0
                    utf8_bytes[2] = 0x80 | ((charcode >> 6) & 0x3F);
2055
0
                    utf8_bytes[3] = 0x80 | (charcode & 0x3F);
2056
0
                    utf8_bytes_filled = 4;
2057
0
                }
2058
0
                else
2059
0
                {
2060
0
                    // unknown character
2061
0
                    ++current_wchar;
2062
0
                    utf8_bytes[0] = wc;
2063
0
                    utf8_bytes_filled = 1;
2064
0
                }
2065
0
            }
2066
0
        }
2067
0
    }
Unexecuted instantiation: _ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIwSt11char_traitsIwESaIwEEEE17fill_buffer_utf16Ev
Unexecuted instantiation: _ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIDsSt11char_traitsIDsESaIDsEEEE17fill_buffer_utf16Ev
Unexecuted instantiation: _ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIDiSt11char_traitsIDiESaIDiEEEE17fill_buffer_utf16Ev
2068
2069
    void fill_buffer_utf32()
2070
0
    {
2071
0
        utf8_bytes_index = 0;
2072
0
2073
0
        if (current_wchar == str.size())
2074
0
        {
2075
0
            utf8_bytes[0] = std::char_traits<char>::eof();
2076
0
            utf8_bytes_filled = 1;
2077
0
        }
2078
0
        else
2079
0
        {
2080
0
            // get the current character
2081
0
            const int wc = static_cast<int>(str[current_wchar++]);
2082
0
2083
0
            // UTF-32 to UTF-8 encoding
2084
0
            if (wc < 0x80)
2085
0
            {
2086
0
                utf8_bytes[0] = wc;
2087
0
                utf8_bytes_filled = 1;
2088
0
            }
2089
0
            else if (wc <= 0x7FF)
2090
0
            {
2091
0
                utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F);
2092
0
                utf8_bytes[1] = 0x80 | (wc & 0x3F);
2093
0
                utf8_bytes_filled = 2;
2094
0
            }
2095
0
            else if (wc <= 0xFFFF)
2096
0
            {
2097
0
                utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F);
2098
0
                utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
2099
0
                utf8_bytes[2] = 0x80 | (wc & 0x3F);
2100
0
                utf8_bytes_filled = 3;
2101
0
            }
2102
0
            else if (wc <= 0x10FFFF)
2103
0
            {
2104
0
                utf8_bytes[0] = 0xF0 | ((wc >> 18 ) & 0x07);
2105
0
                utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F);
2106
0
                utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F);
2107
0
                utf8_bytes[3] = 0x80 | (wc & 0x3F);
2108
0
                utf8_bytes_filled = 4;
2109
0
            }
2110
0
            else
2111
0
            {
2112
0
                // unknown character
2113
0
                utf8_bytes[0] = wc;
2114
0
                utf8_bytes_filled = 1;
2115
0
            }
2116
0
        }
2117
0
    }
Unexecuted instantiation: _ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIwSt11char_traitsIwESaIwEEEE17fill_buffer_utf32Ev
Unexecuted instantiation: _ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIDsSt11char_traitsIDsESaIDsEEEE17fill_buffer_utf32Ev
Unexecuted instantiation: _ZN8nlohmann6detail25wide_string_input_adapterINSt7__cxx1112basic_stringIDiSt11char_traitsIDiESaIDiEEEE17fill_buffer_utf32Ev
2118
2119
  private:
2120
    /// the wstring to process
2121
    const WideStringType& str;
2122
2123
    /// index of the current wchar in str
2124
    std::size_t current_wchar = 0;
2125
2126
    /// a buffer for UTF-8 bytes
2127
    std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};
2128
2129
    /// index to the utf8_codes array for the next valid byte
2130
    std::size_t utf8_bytes_index = 0;
2131
    /// number of valid bytes in the utf8_codes array
2132
    std::size_t utf8_bytes_filled = 0;
2133
};
2134
2135
class input_adapter
2136
{
2137
  public:
2138
    // native support
2139
2140
    /// input adapter for input stream
2141
    input_adapter(std::istream& i)
2142
812
        : ia(std::make_shared<input_stream_adapter>(i)) {}
2143
2144
    /// input adapter for input stream
2145
    input_adapter(std::istream&& i)
2146
0
        : ia(std::make_shared<input_stream_adapter>(i)) {}
2147
2148
    input_adapter(const std::wstring& ws)
2149
0
        : ia(std::make_shared<wide_string_input_adapter<std::wstring>>(ws)) {}
2150
2151
    input_adapter(const std::u16string& ws)
2152
0
        : ia(std::make_shared<wide_string_input_adapter<std::u16string>>(ws)) {}
2153
2154
    input_adapter(const std::u32string& ws)
2155
0
        : ia(std::make_shared<wide_string_input_adapter<std::u32string>>(ws)) {}
2156
2157
    /// input adapter for buffer
2158
    template<typename CharT,
2159
             typename std::enable_if<
2160
                 std::is_pointer<CharT>::value and
2161
                 std::is_integral<typename std::remove_pointer<CharT>::type>::value and
2162
                 sizeof(typename std::remove_pointer<CharT>::type) == 1,
2163
                 int>::type = 0>
2164
    input_adapter(CharT b, std::size_t l)
2165
        : ia(std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(b), l)) {}
2166
2167
    // derived support
2168
2169
    /// input adapter for string literal
2170
    template<typename CharT,
2171
             typename std::enable_if<
2172
                 std::is_pointer<CharT>::value and
2173
                 std::is_integral<typename std::remove_pointer<CharT>::type>::value and
2174
                 sizeof(typename std::remove_pointer<CharT>::type) == 1,
2175
                 int>::type = 0>
2176
    input_adapter(CharT b)
2177
        : input_adapter(reinterpret_cast<const char*>(b),
2178
                        std::strlen(reinterpret_cast<const char*>(b))) {}
2179
2180
    /// input adapter for iterator range with contiguous storage
2181
    template<class IteratorType,
2182
             typename std::enable_if<
2183
                 std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
2184
                 int>::type = 0>
2185
    input_adapter(IteratorType first, IteratorType last)
2186
2.59k
    {
2187
2.59k
#ifndef NDEBUG
2188
2.59k
        // assertion to check that the iterator range is indeed contiguous,
2189
2.59k
        // see http://stackoverflow.com/a/35008842/266378 for more discussion
2190
2.59k
        const auto is_contiguous = std::accumulate(
2191
2.59k
                                       first, last, std::pair<bool, int>(true, 0),
2192
2.59k
                                       [&first](std::pair<bool, int> res, decltype(*first) val)
2193
16.8M
        {
2194
16.8M
            res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
2195
16.8M
            return res;
2196
16.8M
        }).first;
_ZZN8nlohmann6detail13input_adapterC1IN9__gnu_cxx17__normal_iteratorIPKcNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEELi0EEET_SE_ENKUlSt4pairIbiERS5_E_clESG_SH_
Line
Count
Source
2193
50.1k
        {
2194
50.1k
            res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
2195
50.1k
            return res;
2196
50.1k
        }).first;
_ZZN8nlohmann6detail13input_adapterC1IPKcLi0EEET_S5_ENKUlSt4pairIbiERS3_E_clES7_S8_
Line
Count
Source
2193
16.7M
        {
2194
16.7M
            res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
2195
16.7M
            return res;
2196
16.7M
        }).first;
2197
2.59k
        assert(is_contiguous);
2198
2.59k
#endif
2199
2.59k
2200
2.59k
        // assertion to check that each element is 1 byte long
2201
2.59k
        static_assert(
2202
2.59k
            sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
2203
2.59k
            "each element in the iterator range must have the size of 1 byte");
2204
2.59k
2205
2.59k
        const auto len = static_cast<size_t>(std::distance(first, last));
2206
2.59k
        if (JSON_LIKELY(len > 0))
2207
2.59k
        {
2208
2.59k
            // there is at least one element: use the address of first
2209
2.59k
            ia = std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(&(*first)), len);
2210
2.59k
        }
2211
0
        else
2212
0
        {
2213
0
            // the address of first cannot be used: use nullptr
2214
0
            ia = std::make_shared<input_buffer_adapter>(nullptr, len);
2215
0
        }
2216
2.59k
    }
_ZN8nlohmann6detail13input_adapterC2IN9__gnu_cxx17__normal_iteratorIPKcNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEELi0EEET_SE_
Line
Count
Source
2186
160
    {
2187
160
#ifndef NDEBUG
2188
160
        // assertion to check that the iterator range is indeed contiguous,
2189
160
        // see http://stackoverflow.com/a/35008842/266378 for more discussion
2190
160
        const auto is_contiguous = std::accumulate(
2191
160
                                       first, last, std::pair<bool, int>(true, 0),
2192
160
                                       [&first](std::pair<bool, int> res, decltype(*first) val)
2193
160
        {
2194
160
            res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
2195
160
            return res;
2196
160
        }).first;
2197
160
        assert(is_contiguous);
2198
160
#endif
2199
160
2200
160
        // assertion to check that each element is 1 byte long
2201
160
        static_assert(
2202
160
            sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
2203
160
            "each element in the iterator range must have the size of 1 byte");
2204
160
2205
160
        const auto len = static_cast<size_t>(std::distance(first, last));
2206
160
        if (JSON_LIKELY(len > 0))
2207
160
        {
2208
160
            // there is at least one element: use the address of first
2209
160
            ia = std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(&(*first)), len);
2210
160
        }
2211
0
        else
2212
0
        {
2213
0
            // the address of first cannot be used: use nullptr
2214
0
            ia = std::make_shared<input_buffer_adapter>(nullptr, len);
2215
0
        }
2216
160
    }
_ZN8nlohmann6detail13input_adapterC2IPKcLi0EEET_S5_
Line
Count
Source
2186
2.43k
    {
2187
2.43k
#ifndef NDEBUG
2188
2.43k
        // assertion to check that the iterator range is indeed contiguous,
2189
2.43k
        // see http://stackoverflow.com/a/35008842/266378 for more discussion
2190
2.43k
        const auto is_contiguous = std::accumulate(
2191
2.43k
                                       first, last, std::pair<bool, int>(true, 0),
2192
2.43k
                                       [&first](std::pair<bool, int> res, decltype(*first) val)
2193
2.43k
        {
2194
2.43k
            res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
2195
2.43k
            return res;
2196
2.43k
        }).first;
2197
2.43k
        assert(is_contiguous);
2198
2.43k
#endif
2199
2.43k
2200
2.43k
        // assertion to check that each element is 1 byte long
2201
2.43k
        static_assert(
2202
2.43k
            sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
2203
2.43k
            "each element in the iterator range must have the size of 1 byte");
2204
2.43k
2205
2.43k
        const auto len = static_cast<size_t>(std::distance(first, last));
2206
2.43k
        if (JSON_LIKELY(len > 0))
2207
2.43k
        {
2208
2.43k
            // there is at least one element: use the address of first
2209
2.43k
            ia = std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(&(*first)), len);
2210
2.43k
        }
2211
0
        else
2212
0
        {
2213
0
            // the address of first cannot be used: use nullptr
2214
0
            ia = std::make_shared<input_buffer_adapter>(nullptr, len);
2215
0
        }
2216
2.43k
    }
2217
2218
    /// input adapter for array
2219
    template<class T, std::size_t N>
2220
    input_adapter(T (&array)[N])
2221
2.43k
        : input_adapter(std::begin(array), std::end(array)) {}
_ZN8nlohmann6detail13input_adapterC2IKcLm117EEERAT0__T_
Line
Count
Source
2221
812
        : input_adapter(std::begin(array), std::end(array)) {}
_ZN8nlohmann6detail13input_adapterC2IKcLm10282EEERAT0__T_
Line
Count
Source
2221
812
        : input_adapter(std::begin(array), std::end(array)) {}
_ZN8nlohmann6detail13input_adapterC2IKcLm10259EEERAT0__T_
Line
Count
Source
2221
812
        : input_adapter(std::begin(array), std::end(array)) {}
2222
2223
    /// input adapter for contiguous container
2224
    template<class ContiguousContainer, typename
2225
             std::enable_if<not std::is_pointer<ContiguousContainer>::value and
2226
                            std::is_base_of<std::random_access_iterator_tag, typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value,
2227
                            int>::type = 0>
2228
    input_adapter(const ContiguousContainer& c)
2229
160
        : input_adapter(std::begin(c), std::end(c)) {}
2230
2231
    operator input_adapter_t()
2232
3.40k
    {
2233
3.40k
        return ia;
2234
3.40k
    }
2235
2236
  private:
2237
    /// the actual adapter
2238
    input_adapter_t ia = nullptr;
2239
};
2240
}
2241
}
2242
2243
// #include <nlohmann/detail/input/lexer.hpp>
2244
2245
2246
#include <clocale> // localeconv
2247
#include <cstddef> // size_t
2248
#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
2249
#include <cstdio> // snprintf
2250
#include <initializer_list> // initializer_list
2251
#include <string> // char_traits, string
2252
#include <vector> // vector
2253
2254
// #include <nlohmann/detail/macro_scope.hpp>
2255
2256
// #include <nlohmann/detail/input/input_adapters.hpp>
2257
2258
2259
namespace nlohmann
2260
{
2261
namespace detail
2262
{
2263
///////////
2264
// lexer //
2265
///////////
2266
2267
/*!
2268
@brief lexical analysis
2269
2270
This class organizes the lexical analysis during JSON deserialization.
2271
*/
2272
template<typename BasicJsonType>
2273
class lexer
2274
{
2275
    using number_integer_t = typename BasicJsonType::number_integer_t;
2276
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
2277
    using number_float_t = typename BasicJsonType::number_float_t;
2278
    using string_t = typename BasicJsonType::string_t;
2279
2280
  public:
2281
    /// token types for the parser
2282
    enum class token_type
2283
    {
2284
        uninitialized,    ///< indicating the scanner is uninitialized
2285
        literal_true,     ///< the `true` literal
2286
        literal_false,    ///< the `false` literal
2287
        literal_null,     ///< the `null` literal
2288
        value_string,     ///< a string -- use get_string() for actual value
2289
        value_unsigned,   ///< an unsigned integer -- use get_number_unsigned() for actual value
2290
        value_integer,    ///< a signed integer -- use get_number_integer() for actual value
2291
        value_float,      ///< an floating point number -- use get_number_float() for actual value
2292
        begin_array,      ///< the character for array begin `[`
2293
        begin_object,     ///< the character for object begin `{`
2294
        end_array,        ///< the character for array end `]`
2295
        end_object,       ///< the character for object end `}`
2296
        name_separator,   ///< the name separator `:`
2297
        value_separator,  ///< the value separator `,`
2298
        parse_error,      ///< indicating a parse error
2299
        end_of_input,     ///< indicating the end of the input buffer
2300
        literal_or_value  ///< a literal or the begin of a value (only for diagnostics)
2301
    };
2302
2303
    /// return name of values of type token_type (only used for errors)
2304
    static const char* token_type_name(const token_type t) noexcept
2305
8
    {
2306
8
        switch (t)
2307
8
        {
2308
8
            case token_type::uninitialized:
2309
0
                return "<uninitialized>";
2310
8
            case token_type::literal_true:
2311
0
                return "true literal";
2312
8
            case token_type::literal_false:
2313
0
                return "false literal";
2314
8
            case token_type::literal_null:
2315
0
                return "null literal";
2316
8
            case token_type::value_string:
2317
0
                return "string literal";
2318
8
            case lexer::token_type::value_unsigned:
2319
0
            case lexer::token_type::value_integer:
2320
0
            case lexer::token_type::value_float:
2321
0
                return "number literal";
2322
0
            case token_type::begin_array:
2323
0
                return "'['";
2324
0
            case token_type::begin_object:
2325
0
                return "'{'";
2326
0
            case token_type::end_array:
2327
0
                return "']'";
2328
0
            case token_type::end_object:
2329
0
                return "'}'";
2330
0
            case token_type::name_separator:
2331
0
                return "':'";
2332
0
            case token_type::value_separator:
2333
0
                return "','";
2334
0
            case token_type::parse_error:
2335
0
                return "<parse error>";
2336
4
            case token_type::end_of_input:
2337
4
                return "end of input";
2338
4
            case token_type::literal_or_value:
2339
4
                return "'[', '{', or a literal";
2340
0
            // LCOV_EXCL_START
2341
0
            default: // catch non-enum values
2342
0
                return "unknown token";
2343
0
                // LCOV_EXCL_STOP
2344
0
        }
2345
0
    }
2346
2347
    explicit lexer(detail::input_adapter_t&& adapter)
2348
3.40k
        : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {}
2349
2350
    // delete because of pointer members
2351
    lexer(const lexer&) = delete;
2352
    lexer& operator=(lexer&) = delete;
2353
2354
  private:
2355
    /////////////////////
2356
    // locales
2357
    /////////////////////
2358
2359
    /// return the locale-dependent decimal point
2360
    static char get_decimal_point() noexcept
2361
3.40k
    {
2362
3.40k
        const auto loc = localeconv();
2363
3.40k
        assert(loc != nullptr);
2364
3.40k
        return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
2365
3.40k
    }
2366
2367
    /////////////////////
2368
    // scan functions
2369
    /////////////////////
2370
2371
    /*!
2372
    @brief get codepoint from 4 hex characters following `\u`
2373
2374
    For input "\u c1 c2 c3 c4" the codepoint is:
2375
      (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4
2376
    = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)
2377
2378
    Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f'
2379
    must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The
2380
    conversion is done by subtracting the offset (0x30, 0x37, and 0x57)
2381
    between the ASCII value of the character and the desired integer value.
2382
2383
    @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or
2384
            non-hex character)
2385
    */
2386
    int get_codepoint()
2387
0
    {
2388
0
        // this function only makes sense after reading `\u`
2389
0
        assert(current == 'u');
2390
0
        int codepoint = 0;
2391
0
2392
0
        const auto factors = { 12, 8, 4, 0 };
2393
0
        for (const auto factor : factors)
2394
0
        {
2395
0
            get();
2396
0
2397
0
            if (current >= '0' and current <= '9')
2398
0
            {
2399
0
                codepoint += ((current - 0x30) << factor);
2400
0
            }
2401
0
            else if (current >= 'A' and current <= 'F')
2402
0
            {
2403
0
                codepoint += ((current - 0x37) << factor);
2404
0
            }
2405
0
            else if (current >= 'a' and current <= 'f')
2406
0
            {
2407
0
                codepoint += ((current - 0x57) << factor);
2408
0
            }
2409
0
            else
2410
0
            {
2411
0
                return -1;
2412
0
            }
2413
0
        }
2414
0
2415
0
        assert(0x0000 <= codepoint and codepoint <= 0xFFFF);
2416
0
        return codepoint;
2417
0
    }
2418
2419
    /*!
2420
    @brief check if the next byte(s) are inside a given range
2421
2422
    Adds the current byte and, for each passed range, reads a new byte and
2423
    checks if it is inside the range. If a violation was detected, set up an
2424
    error message and return false. Otherwise, return true.
2425
2426
    @param[in] ranges  list of integers; interpreted as list of pairs of
2427
                       inclusive lower and upper bound, respectively
2428
2429
    @pre The passed list @a ranges must have 2, 4, or 6 elements; that is,
2430
         1, 2, or 3 pairs. This precondition is enforced by an assertion.
2431
2432
    @return true if and only if no range violation was detected
2433
    */
2434
    bool next_byte_in_range(std::initializer_list<int> ranges)
2435
0
    {
2436
0
        assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6);
2437
0
        add(current);
2438
0
2439
0
        for (auto range = ranges.begin(); range != ranges.end(); ++range)
2440
0
        {
2441
0
            get();
2442
0
            if (JSON_LIKELY(*range <= current and current <= *(++range)))
2443
0
            {
2444
0
                add(current);
2445
0
            }
2446
0
            else
2447
0
            {
2448
0
                error_message = "invalid string: ill-formed UTF-8 byte";
2449
0
                return false;
2450
0
            }
2451
0
        }
2452
0
2453
0
        return true;
2454
0
    }
2455
2456
    /*!
2457
    @brief scan a string literal
2458
2459
    This function scans a string according to Sect. 7 of RFC 7159. While
2460
    scanning, bytes are escaped and copied into buffer token_buffer. Then the
2461
    function returns successfully, token_buffer is *not* null-terminated (as it
2462
    may contain \0 bytes), and token_buffer.size() is the number of bytes in the
2463
    string.
2464
2465
    @return token_type::value_string if string could be successfully scanned,
2466
            token_type::parse_error otherwise
2467
2468
    @note In case of errors, variable error_message contains a textual
2469
          description.
2470
    */
2471
    token_type scan_string()
2472
1.26M
    {
2473
1.26M
        // reset token_buffer (ignore opening quote)
2474
1.26M
        reset();
2475
1.26M
2476
1.26M
        // we entered the function by reading an open quote
2477
1.26M
        assert(current == '\"');
2478
1.26M
2479
11.1M
        while (true)
2480
11.1M
        {
2481
11.1M
            // get next character
2482
11.1M
            switch (get())
2483
11.1M
            {
2484
11.1M
                // end of file while parsing string
2485
11.1M
                case std::char_traits<char>::eof():
2486
0
                {
2487
0
                    error_message = "invalid string: missing closing quote";
2488
0
                    return token_type::parse_error;
2489
11.1M
                }
2490
11.1M
2491
11.1M
                // closing quote
2492
11.1M
                case '\"':
2493
1.26M
                {
2494
1.26M
                    return token_type::value_string;
2495
11.1M
                }
2496
11.1M
2497
11.1M
                // escapes
2498
11.1M
                case '\\':
2499
0
                {
2500
0
                    switch (get())
2501
0
                    {
2502
0
                        // quotation mark
2503
0
                        case '\"':
2504
0
                            add('\"');
2505
0
                            break;
2506
0
                        // reverse solidus
2507
0
                        case '\\':
2508
0
                            add('\\');
2509
0
                            break;
2510
0
                        // solidus
2511
0
                        case '/':
2512
0
                            add('/');
2513
0
                            break;
2514
0
                        // backspace
2515
0
                        case 'b':
2516
0
                            add('\b');
2517
0
                            break;
2518
0
                        // form feed
2519
0
                        case 'f':
2520
0
                            add('\f');
2521
0
                            break;
2522
0
                        // line feed
2523
0
                        case 'n':
2524
0
                            add('\n');
2525
0
                            break;
2526
0
                        // carriage return
2527
0
                        case 'r':
2528
0
                            add('\r');
2529
0
                            break;
2530
0
                        // tab
2531
0
                        case 't':
2532
0
                            add('\t');
2533
0
                            break;
2534
0
2535
0
                        // unicode escapes
2536
0
                        case 'u':
2537
0
                        {
2538
0
                            const int codepoint1 = get_codepoint();
2539
0
                            int codepoint = codepoint1; // start with codepoint1
2540
0
2541
0
                            if (JSON_UNLIKELY(codepoint1 == -1))
2542
0
                            {
2543
0
                                error_message = "invalid string: '\\u' must be followed by 4 hex digits";
2544
0
                                return token_type::parse_error;
2545
0
                            }
2546
0
2547
0
                            // check if code point is a high surrogate
2548
0
                            if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF)
2549
0
                            {
2550
0
                                // expect next \uxxxx entry
2551
0
                                if (JSON_LIKELY(get() == '\\' and get() == 'u'))
2552
0
                                {
2553
0
                                    const int codepoint2 = get_codepoint();
2554
0
2555
0
                                    if (JSON_UNLIKELY(codepoint2 == -1))
2556
0
                                    {
2557
0
                                        error_message = "invalid string: '\\u' must be followed by 4 hex digits";
2558
0
                                        return token_type::parse_error;
2559
0
                                    }
2560
0
2561
0
                                    // check if codepoint2 is a low surrogate
2562
0
                                    if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF))
2563
0
                                    {
2564
0
                                        // overwrite codepoint
2565
0
                                        codepoint =
2566
0
                                            // high surrogate occupies the most significant 22 bits
2567
0
                                            (codepoint1 << 10)
2568
0
                                            // low surrogate occupies the least significant 15 bits
2569
0
                                            + codepoint2
2570
0
                                            // there is still the 0xD800, 0xDC00 and 0x10000 noise
2571
0
                                            // in the result so we have to subtract with:
2572
0
                                            // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
2573
0
                                            - 0x35FDC00;
2574
0
                                    }
2575
0
                                    else
2576
0
                                    {
2577
0
                                        error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF";
2578
0
                                        return token_type::parse_error;
2579
0
                                    }
2580
0
                                }
2581
0
                                else
2582
0
                                {
2583
0
                                    error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF";
2584
0
                                    return token_type::parse_error;
2585
0
                                }
2586
0
                            }
2587
0
                            else
2588
0
                            {
2589
0
                                if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF))
2590
0
                                {
2591
0
                                    error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF";
2592
0
                                    return token_type::parse_error;
2593
0
                                }
2594
0
                            }
2595
0
2596
0
                            // result of the above calculation yields a proper codepoint
2597
0
                            assert(0x00 <= codepoint and codepoint <= 0x10FFFF);
2598
0
2599
0
                            // translate codepoint into bytes
2600
0
                            if (codepoint < 0x80)
2601
0
                            {
2602
0
                                // 1-byte characters: 0xxxxxxx (ASCII)
2603
0
                                add(codepoint);
2604
0
                            }
2605
0
                            else if (codepoint <= 0x7FF)
2606
0
                            {
2607
0
                                // 2-byte characters: 110xxxxx 10xxxxxx
2608
0
                                add(0xC0 | (codepoint >> 6));
2609
0
                                add(0x80 | (codepoint & 0x3F));
2610
0
                            }
2611
0
                            else if (codepoint <= 0xFFFF)
2612
0
                            {
2613
0
                                // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
2614
0
                                add(0xE0 | (codepoint >> 12));
2615
0
                                add(0x80 | ((codepoint >> 6) & 0x3F));
2616
0
                                add(0x80 | (codepoint & 0x3F));
2617
0
                            }
2618
0
                            else
2619
0
                            {
2620
0
                                // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
2621
0
                                add(0xF0 | (codepoint >> 18));
2622
0
                                add(0x80 | ((codepoint >> 12) & 0x3F));
2623
0
                                add(0x80 | ((codepoint >> 6) & 0x3F));
2624
0
                                add(0x80 | (codepoint & 0x3F));
2625
0
                            }
2626
0
2627
0
                            break;
2628
0
                        }
2629
0
2630
0
                        // other characters after escape
2631
0
                        default:
2632
0
                            error_message = "invalid string: forbidden character after backslash";
2633
0
                            return token_type::parse_error;
2634
0
                    }
2635
0
2636
0
                    break;
2637
0
                }
2638
0
2639
0
                // invalid control characters
2640
0
                case 0x00:
2641
0
                case 0x01:
2642
0
                case 0x02:
2643
0
                case 0x03:
2644
0
                case 0x04:
2645
0
                case 0x05:
2646
0
                case 0x06:
2647
0
                case 0x07:
2648
0
                case 0x08:
2649
0
                case 0x09:
2650
0
                case 0x0A:
2651
0
                case 0x0B:
2652
0
                case 0x0C:
2653
0
                case 0x0D:
2654
0
                case 0x0E:
2655
0
                case 0x0F:
2656
0
                case 0x10:
2657
0
                case 0x11:
2658
0
                case 0x12:
2659
0
                case 0x13:
2660
0
                case 0x14:
2661
0
                case 0x15:
2662
0
                case 0x16:
2663
0
                case 0x17:
2664
0
                case 0x18:
2665
0
                case 0x19:
2666
0
                case 0x1A:
2667
0
                case 0x1B:
2668
0
                case 0x1C:
2669
0
                case 0x1D:
2670
0
                case 0x1E:
2671
0
                case 0x1F:
2672
0
                {
2673
0
                    error_message = "invalid string: control character must be escaped";
2674
0
                    return token_type::parse_error;
2675
0
                }
2676
0
2677
0
                // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))
2678
9.90M
                case 0x20:
2679
9.90M
                case 0x21:
2680
9.90M
                case 0x23:
2681
9.90M
                case 0x24:
2682
9.90M
                case 0x25:
2683
9.90M
                case 0x26:
2684
9.90M
                case 0x27:
2685
9.90M
                case 0x28:
2686
9.90M
                case 0x29:
2687
9.90M
                case 0x2A:
2688
9.90M
                case 0x2B:
2689
9.90M
                case 0x2C:
2690
9.90M
                case 0x2D:
2691
9.90M
                case 0x2E:
2692
9.90M
                case 0x2F:
2693
9.90M
                case 0x30:
2694
9.90M
                case 0x31:
2695
9.90M
                case 0x32:
2696
9.90M
                case 0x33:
2697
9.90M
                case 0x34:
2698
9.90M
                case 0x35:
2699
9.90M
                case 0x36:
2700
9.90M
                case 0x37:
2701
9.90M
                case 0x38:
2702
9.90M
                case 0x39:
2703
9.90M
                case 0x3A:
2704
9.90M
                case 0x3B:
2705
9.90M
                case 0x3C:
2706
9.90M
                case 0x3D:
2707
9.90M
                case 0x3E:
2708
9.90M
                case 0x3F:
2709
9.90M
                case 0x40:
2710
9.90M
                case 0x41:
2711
9.90M
                case 0x42:
2712
9.90M
                case 0x43:
2713
9.90M
                case 0x44:
2714
9.90M
                case 0x45:
2715
9.90M
                case 0x46:
2716
9.90M
                case 0x47:
2717
9.90M
                case 0x48:
2718
9.90M
                case 0x49:
2719
9.90M
                case 0x4A:
2720
9.90M
                case 0x4B:
2721
9.90M
                case 0x4C:
2722
9.90M
                case 0x4D:
2723
9.90M
                case 0x4E:
2724
9.90M
                case 0x4F:
2725
9.90M
                case 0x50:
2726
9.90M
                case 0x51:
2727
9.90M
                case 0x52:
2728
9.90M
                case 0x53:
2729
9.90M
                case 0x54:
2730
9.90M
                case 0x55:
2731
9.90M
                case 0x56:
2732
9.90M
                case 0x57:
2733
9.90M
                case 0x58:
2734
9.90M
                case 0x59:
2735
9.90M
                case 0x5A:
2736
9.90M
                case 0x5B:
2737
9.90M
                case 0x5D:
2738
9.90M
                case 0x5E:
2739
9.90M
                case 0x5F:
2740
9.90M
                case 0x60:
2741
9.90M
                case 0x61:
2742
9.90M
                case 0x62:
2743
9.90M
                case 0x63:
2744
9.90M
                case 0x64:
2745
9.90M
                case 0x65:
2746
9.90M
                case 0x66:
2747
9.90M
                case 0x67:
2748
9.90M
                case 0x68:
2749
9.90M
                case 0x69:
2750
9.90M
                case 0x6A:
2751
9.90M
                case 0x6B:
2752
9.90M
                case 0x6C:
2753
9.90M
                case 0x6D:
2754
9.90M
                case 0x6E:
2755
9.90M
                case 0x6F:
2756
9.90M
                case 0x70:
2757
9.90M
                case 0x71:
2758
9.90M
                case 0x72:
2759
9.90M
                case 0x73:
2760
9.90M
                case 0x74:
2761
9.90M
                case 0x75:
2762
9.90M
                case 0x76:
2763
9.90M
                case 0x77:
2764
9.90M
                case 0x78:
2765
9.90M
                case 0x79:
2766
9.90M
                case 0x7A:
2767
9.90M
                case 0x7B:
2768
9.90M
                case 0x7C:
2769
9.90M
                case 0x7D:
2770
9.90M
                case 0x7E:
2771
9.90M
                case 0x7F:
2772
9.90M
                {
2773
9.90M
                    add(current);
2774
9.90M
                    break;
2775
9.90M
                }
2776
9.90M
2777
9.90M
                // U+0080..U+07FF: bytes C2..DF 80..BF
2778
9.90M
                case 0xC2:
2779
0
                case 0xC3:
2780
0
                case 0xC4:
2781
0
                case 0xC5:
2782
0
                case 0xC6:
2783
0
                case 0xC7:
2784
0
                case 0xC8:
2785
0
                case 0xC9:
2786
0
                case 0xCA:
2787
0
                case 0xCB:
2788
0
                case 0xCC:
2789
0
                case 0xCD:
2790
0
                case 0xCE:
2791
0
                case 0xCF:
2792
0
                case 0xD0:
2793
0
                case 0xD1:
2794
0
                case 0xD2:
2795
0
                case 0xD3:
2796
0
                case 0xD4:
2797
0
                case 0xD5:
2798
0
                case 0xD6:
2799
0
                case 0xD7:
2800
0
                case 0xD8:
2801
0
                case 0xD9:
2802
0
                case 0xDA:
2803
0
                case 0xDB:
2804
0
                case 0xDC:
2805
0
                case 0xDD:
2806
0
                case 0xDE:
2807
0
                case 0xDF:
2808
0
                {
2809
0
                    if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF})))
2810
0
                    {
2811
0
                        return token_type::parse_error;
2812
0
                    }
2813
0
                    break;
2814
0
                }
2815
0
2816
0
                // U+0800..U+0FFF: bytes E0 A0..BF 80..BF
2817
0
                case 0xE0:
2818
0
                {
2819
0
                    if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))
2820
0
                    {
2821
0
                        return token_type::parse_error;
2822
0
                    }
2823
0
                    break;
2824
0
                }
2825
0
2826
0
                // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF
2827
0
                // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF
2828
0
                case 0xE1:
2829
0
                case 0xE2:
2830
0
                case 0xE3:
2831
0
                case 0xE4:
2832
0
                case 0xE5:
2833
0
                case 0xE6:
2834
0
                case 0xE7:
2835
0
                case 0xE8:
2836
0
                case 0xE9:
2837
0
                case 0xEA:
2838
0
                case 0xEB:
2839
0
                case 0xEC:
2840
0
                case 0xEE:
2841
0
                case 0xEF:
2842
0
                {
2843
0
                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))
2844
0
                    {
2845
0
                        return token_type::parse_error;
2846
0
                    }
2847
0
                    break;
2848
0
                }
2849
0
2850
0
                // U+D000..U+D7FF: bytes ED 80..9F 80..BF
2851
0
                case 0xED:
2852
0
                {
2853
0
                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))
2854
0
                    {
2855
0
                        return token_type::parse_error;
2856
0
                    }
2857
0
                    break;
2858
0
                }
2859
0
2860
0
                // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
2861
0
                case 0xF0:
2862
0
                {
2863
0
                    if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
2864
0
                    {
2865
0
                        return token_type::parse_error;
2866
0
                    }
2867
0
                    break;
2868
0
                }
2869
0
2870
0
                // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
2871
0
                case 0xF1:
2872
0
                case 0xF2:
2873
0
                case 0xF3:
2874
0
                {
2875
0
                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
2876
0
                    {
2877
0
                        return token_type::parse_error;
2878
0
                    }
2879
0
                    break;
2880
0
                }
2881
0
2882
0
                // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
2883
0
                case 0xF4:
2884
0
                {
2885
0
                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))
2886
0
                    {
2887
0
                        return token_type::parse_error;
2888
0
                    }
2889
0
                    break;
2890
0
                }
2891
0
2892
0
                // remaining bytes (80..C1 and F5..FF) are ill-formed
2893
0
                default:
2894
0
                {
2895
0
                    error_message = "invalid string: ill-formed UTF-8 byte";
2896
0
                    return token_type::parse_error;
2897
0
                }
2898
11.1M
            }
2899
11.1M
        }
2900
1.26M
    }
2901
2902
    static void strtof(float& f, const char* str, char** endptr) noexcept
2903
    {
2904
        f = std::strtof(str, endptr);
2905
    }
2906
2907
    static void strtof(double& f, const char* str, char** endptr) noexcept
2908
234k
    {
2909
234k
        f = std::strtod(str, endptr);
2910
234k
    }
2911
2912
    static void strtof(long double& f, const char* str, char** endptr) noexcept
2913
    {
2914
        f = std::strtold(str, endptr);
2915
    }
2916
2917
    /*!
2918
    @brief scan a number literal
2919
2920
    This function scans a string according to Sect. 6 of RFC 7159.
2921
2922
    The function is realized with a deterministic finite state machine derived
2923
    from the grammar described in RFC 7159. Starting in state "init", the
2924
    input is read and used to determined the next state. Only state "done"
2925
    accepts the number. State "error" is a trap state to model errors. In the
2926
    table below, "anything" means any character but the ones listed before.
2927
2928
    state    | 0        | 1-9      | e E      | +       | -       | .        | anything
2929
    ---------|----------|----------|----------|---------|---------|----------|-----------
2930
    init     | zero     | any1     | [error]  | [error] | minus   | [error]  | [error]
2931
    minus    | zero     | any1     | [error]  | [error] | [error] | [error]  | [error]
2932
    zero     | done     | done     | exponent | done    | done    | decimal1 | done
2933
    any1     | any1     | any1     | exponent | done    | done    | decimal1 | done
2934
    decimal1 | decimal2 | [error]  | [error]  | [error] | [error] | [error]  | [error]
2935
    decimal2 | decimal2 | decimal2 | exponent | done    | done    | done     | done
2936
    exponent | any2     | any2     | [error]  | sign    | sign    | [error]  | [error]
2937
    sign     | any2     | any2     | [error]  | [error] | [error] | [error]  | [error]
2938
    any2     | any2     | any2     | done     | done    | done    | done     | done
2939
2940
    The state machine is realized with one label per state (prefixed with
2941
    "scan_number_") and `goto` statements between them. The state machine
2942
    contains cycles, but any cycle can be left when EOF is read. Therefore,
2943
    the function is guaranteed to terminate.
2944
2945
    During scanning, the read bytes are stored in token_buffer. This string is
2946
    then converted to a signed integer, an unsigned integer, or a
2947
    floating-point number.
2948
2949
    @return token_type::value_unsigned, token_type::value_integer, or
2950
            token_type::value_float if number could be successfully scanned,
2951
            token_type::parse_error otherwise
2952
2953
    @note The scanner is independent of the current locale. Internally, the
2954
          locale's decimal point is used instead of `.` to work with the
2955
          locale-dependent converters.
2956
    */
2957
    token_type scan_number()
2958
586k
    {
2959
586k
        // reset token_buffer to store the number's bytes
2960
586k
        reset();
2961
586k
2962
586k
        // the type of the parsed number; initially set to unsigned; will be
2963
586k
        // changed if minus sign, decimal point or exponent is read
2964
586k
        token_type number_type = token_type::value_unsigned;
2965
586k
2966
586k
        // state (init): we just found out we need to scan a number
2967
586k
        switch (current)
2968
586k
        {
2969
586k
            case '-':
2970
37.4k
            {
2971
37.4k
                add(current);
2972
37.4k
                goto scan_number_minus;
2973
586k
            }
2974
586k
2975
586k
            case '0':
2976
78.9k
            {
2977
78.9k
                add(current);
2978
78.9k
                goto scan_number_zero;
2979
586k
            }
2980
586k
2981
586k
            case '1':
2982
469k
            case '2':
2983
469k
            case '3':
2984
469k
            case '4':
2985
469k
            case '5':
2986
469k
            case '6':
2987
469k
            case '7':
2988
469k
            case '8':
2989
469k
            case '9':
2990
469k
            {
2991
469k
                add(current);
2992
469k
                goto scan_number_any1;
2993
469k
            }
2994
469k
2995
469k
            // LCOV_EXCL_START
2996
469k
            default:
2997
0
            {
2998
0
                // all other characters are rejected outside scan_number()
2999
0
                assert(false);
3000
0
            }
3001
586k
                // LCOV_EXCL_STOP
3002
586k
        }
3003
586k
3004
586k
scan_number_minus:
3005
37.4k
        // state: we just parsed a leading minus sign
3006
37.4k
        number_type = token_type::value_integer;
3007
37.4k
        switch (get())
3008
37.4k
        {
3009
37.4k
            case '0':
3010
0
            {
3011
0
                add(current);
3012
0
                goto scan_number_zero;
3013
37.4k
            }
3014
37.4k
3015
37.4k
            case '1':
3016
37.4k
            case '2':
3017
37.4k
            case '3':
3018
37.4k
            case '4':
3019
37.4k
            case '5':
3020
37.4k
            case '6':
3021
37.4k
            case '7':
3022
37.4k
            case '8':
3023
37.4k
            case '9':
3024
37.4k
            {
3025
37.4k
                add(current);
3026
37.4k
                goto scan_number_any1;
3027
37.4k
            }
3028
37.4k
3029
37.4k
            default:
3030
0
            {
3031
0
                error_message = "invalid number; expected digit after '-'";
3032
0
                return token_type::parse_error;
3033
78.9k
            }
3034
78.9k
        }
3035
78.9k
3036
78.9k
scan_number_zero:
3037
78.9k
        // state: we just parse a zero (maybe with a leading minus sign)
3038
78.9k
        switch (get())
3039
78.9k
        {
3040
78.9k
            case '.':
3041
812
            {
3042
812
                add(decimal_point_char);
3043
812
                goto scan_number_decimal1;
3044
78.9k
            }
3045
78.9k
3046
78.9k
            case 'e':
3047
0
            case 'E':
3048
0
            {
3049
0
                add(current);
3050
0
                goto scan_number_exponent;
3051
0
            }
3052
0
3053
78.1k
            default:
3054
78.1k
                goto scan_number_done;
3055
1.72M
        }
3056
1.72M
3057
1.72M
scan_number_any1:
3058
1.72M
        // state: we just parsed a number 0-9 (maybe with a leading minus sign)
3059
1.72M
        switch (get())
3060
1.72M
        {
3061
1.72M
            case '0':
3062
1.22M
            case '1':
3063
1.22M
            case '2':
3064
1.22M
            case '3':
3065
1.22M
            case '4':
3066
1.22M
            case '5':
3067
1.22M
            case '6':
3068
1.22M
            case '7':
3069
1.22M
            case '8':
3070
1.22M
            case '9':
3071
1.22M
            {
3072
1.22M
                add(current);
3073
1.22M
                goto scan_number_any1;
3074
1.22M
            }
3075
1.22M
3076
1.22M
            case '.':
3077
233k
            {
3078
233k
                add(decimal_point_char);
3079
233k
                goto scan_number_decimal1;
3080
1.22M
            }
3081
1.22M
3082
1.22M
            case 'e':
3083
0
            case 'E':
3084
0
            {
3085
0
                add(current);
3086
0
                goto scan_number_exponent;
3087
0
            }
3088
0
3089
273k
            default:
3090
273k
                goto scan_number_done;
3091
234k
        }
3092
234k
3093
234k
scan_number_decimal1:
3094
234k
        // state: we just parsed a decimal point
3095
234k
        number_type = token_type::value_float;
3096
234k
        switch (get())
3097
234k
        {
3098
234k
            case '0':
3099
234k
            case '1':
3100
234k
            case '2':
3101
234k
            case '3':
3102
234k
            case '4':
3103
234k
            case '5':
3104
234k
            case '6':
3105
234k
            case '7':
3106
234k
            case '8':
3107
234k
            case '9':
3108
234k
            {
3109
234k
                add(current);
3110
234k
                goto scan_number_decimal2;
3111
234k
            }
3112
234k
3113
234k
            default:
3114
0
            {
3115
0
                error_message = "invalid number; expected digit after '.'";
3116
0
                return token_type::parse_error;
3117
1.00M
            }
3118
1.00M
        }
3119
1.00M
3120
1.00M
scan_number_decimal2:
3121
1.00M
        // we just parsed at least one number after a decimal point
3122
1.00M
        switch (get())
3123
1.00M
        {
3124
1.00M
            case '0':
3125
768k
            case '1':
3126
768k
            case '2':
3127
768k
            case '3':
3128
768k
            case '4':
3129
768k
            case '5':
3130
768k
            case '6':
3131
768k
            case '7':
3132
768k
            case '8':
3133
768k
            case '9':
3134
768k
            {
3135
768k
                add(current);
3136
768k
                goto scan_number_decimal2;
3137
768k
            }
3138
768k
3139
768k
            case 'e':
3140
0
            case 'E':
3141
0
            {
3142
0
                add(current);
3143
0
                goto scan_number_exponent;
3144
0
            }
3145
0
3146
234k
            default:
3147
234k
                goto scan_number_done;
3148
0
        }
3149
0
3150
0
scan_number_exponent:
3151
0
        // we just parsed an exponent
3152
0
        number_type = token_type::value_float;
3153
0
        switch (get())
3154
0
        {
3155
0
            case '+':
3156
0
            case '-':
3157
0
            {
3158
0
                add(current);
3159
0
                goto scan_number_sign;
3160
0
            }
3161
0
3162
0
            case '0':
3163
0
            case '1':
3164
0
            case '2':
3165
0
            case '3':
3166
0
            case '4':
3167
0
            case '5':
3168
0
            case '6':
3169
0
            case '7':
3170
0
            case '8':
3171
0
            case '9':
3172
0
            {
3173
0
                add(current);
3174
0
                goto scan_number_any2;
3175
0
            }
3176
0
3177
0
            default:
3178
0
            {
3179
0
                error_message =
3180
0
                    "invalid number; expected '+', '-', or digit after exponent";
3181
0
                return token_type::parse_error;
3182
0
            }
3183
0
        }
3184
0
3185
0
scan_number_sign:
3186
0
        // we just parsed an exponent sign
3187
0
        switch (get())
3188
0
        {
3189
0
            case '0':
3190
0
            case '1':
3191
0
            case '2':
3192
0
            case '3':
3193
0
            case '4':
3194
0
            case '5':
3195
0
            case '6':
3196
0
            case '7':
3197
0
            case '8':
3198
0
            case '9':
3199
0
            {
3200
0
                add(current);
3201
0
                goto scan_number_any2;
3202
0
            }
3203
0
3204
0
            default:
3205
0
            {
3206
0
                error_message = "invalid number; expected digit after exponent sign";
3207
0
                return token_type::parse_error;
3208
0
            }
3209
0
        }
3210
0
3211
0
scan_number_any2:
3212
0
        // we just parsed a number after the exponent or exponent sign
3213
0
        switch (get())
3214
0
        {
3215
0
            case '0':
3216
0
            case '1':
3217
0
            case '2':
3218
0
            case '3':
3219
0
            case '4':
3220
0
            case '5':
3221
0
            case '6':
3222
0
            case '7':
3223
0
            case '8':
3224
0
            case '9':
3225
0
            {
3226
0
                add(current);
3227
0
                goto scan_number_any2;
3228
0
            }
3229
0
3230
0
            default:
3231
0
                goto scan_number_done;
3232
586k
        }
3233
586k
3234
586k
scan_number_done:
3235
586k
        // unget the character after the number (we only read it to know that
3236
586k
        // we are done scanning a number)
3237
586k
        unget();
3238
586k
3239
586k
        char* endptr = nullptr;
3240
586k
        errno = 0;
3241
586k
3242
586k
        // try to parse integers first and fall back to floats
3243
586k
        if (number_type == token_type::value_unsigned)
3244
314k
        {
3245
314k
            const auto x = std::strtoull(token_buffer.data(), &endptr, 10);
3246
314k
3247
314k
            // we checked the number format before
3248
314k
            assert(endptr == token_buffer.data() + token_buffer.size());
3249
314k
3250
314k
            if (errno == 0)
3251
314k
            {
3252
314k
                value_unsigned = static_cast<number_unsigned_t>(x);
3253
314k
                if (value_unsigned == x)
3254
314k
                {
3255
314k
                    return token_type::value_unsigned;
3256
314k
                }
3257
271k
            }
3258
271k
        }
3259
271k
        else if (number_type == token_type::value_integer)
3260
37.4k
        {
3261
37.4k
            const auto x = std::strtoll(token_buffer.data(), &endptr, 10);
3262
37.4k
3263
37.4k
            // we checked the number format before
3264
37.4k
            assert(endptr == token_buffer.data() + token_buffer.size());
3265
37.4k
3266
37.4k
            if (errno == 0)
3267
37.4k
            {
3268
37.4k
                value_integer = static_cast<number_integer_t>(x);
3269
37.4k
                if (value_integer == x)
3270
37.4k
                {
3271
37.4k
                    return token_type::value_integer;
3272
37.4k
                }
3273
234k
            }
3274
37.4k
        }
3275
234k
3276
234k
        // this code is reached if we parse a floating-point number or if an
3277
234k
        // integer conversion above failed
3278
234k
        strtof(value_float, token_buffer.data(), &endptr);
3279
234k
3280
234k
        // we checked the number format before
3281
234k
        assert(endptr == token_buffer.data() + token_buffer.size());
3282
234k
3283
234k
        return token_type::value_float;
3284
234k
    }
3285
3286
    /*!
3287
    @param[in] literal_text  the literal text to expect
3288
    @param[in] length        the length of the passed literal text
3289
    @param[in] return_type   the token type to return on success
3290
    */
3291
    token_type scan_literal(const char* literal_text, const std::size_t length,
3292
                            token_type return_type)
3293
4.09k
    {
3294
4.09k
        assert(current == literal_text[0]);
3295
16.3k
        for (std::size_t i = 1; i < length; ++i)
3296
12.2k
        {
3297
12.2k
            if (JSON_UNLIKELY(get() != literal_text[i]))
3298
12.2k
            {
3299
0
                error_message = "invalid literal";
3300
0
                return token_type::parse_error;
3301
0
            }
3302
12.2k
        }
3303
4.09k
        return return_type;
3304
4.09k
    }
3305
3306
    /////////////////////
3307
    // input management
3308
    /////////////////////
3309
3310
    /// reset token_buffer; current character is beginning of token
3311
    void reset() noexcept
3312
1.84M
    {
3313
1.84M
        token_buffer.clear();
3314
1.84M
        token_string.clear();
3315
1.84M
        token_string.push_back(std::char_traits<char>::to_char_type(current));
3316
1.84M
    }
3317
3318
    /*
3319
    @brief get next character from the input
3320
3321
    This function provides the interface to the used input adapter. It does
3322
    not throw in case the input reached EOF, but returns a
3323
    `std::char_traits<char>::eof()` in that case.  Stores the scanned characters
3324
    for use in error messages.
3325
3326
    @return character read from the input
3327
    */
3328
    std::char_traits<char>::int_type get()
3329
19.2M
    {
3330
19.2M
        ++chars_read;
3331
19.2M
        if (next_unget)
3332
589k
        {
3333
589k
            // just reset the next_unget variable and work with current
3334
589k
            next_unget = false;
3335
589k
        }
3336
18.6M
        else
3337
18.6M
        {
3338
18.6M
            current = ia->get_character();
3339
18.6M
        }
3340
19.2M
3341
19.2M
        if (JSON_LIKELY(current != std::char_traits<char>::eof()))
3342
19.2M
        {
3343
19.2M
            token_string.push_back(std::char_traits<char>::to_char_type(current));
3344
19.2M
        }
3345
19.2M
        return current;
3346
19.2M
    }
3347
3348
    /*!
3349
    @brief unget current character (read it again on next get)
3350
3351
    We implement unget by setting variable next_unget to true. The input is not
3352
    changed - we just simulate ungetting by modifying chars_read and
3353
    token_string. The next call to get() will behave as if the unget character
3354
    is read again.
3355
    */
3356
    void unget()
3357
589k
    {
3358
589k
        next_unget = true;
3359
589k
        --chars_read;
3360
589k
        if (JSON_LIKELY(current != std::char_traits<char>::eof()))
3361
589k
        {
3362
589k
            assert(token_string.size() != 0);
3363
589k
            token_string.pop_back();
3364
589k
        }
3365
589k
    }
3366
3367
    /// add a character to token_buffer
3368
    void add(int c)
3369
12.9M
    {
3370
12.9M
        token_buffer.push_back(std::char_traits<char>::to_char_type(c));
3371
12.9M
    }
3372
3373
  public:
3374
    /////////////////////
3375
    // value getters
3376
    /////////////////////
3377
3378
    /// return integer value
3379
    constexpr number_integer_t get_number_integer() const noexcept
3380
37.4k
    {
3381
37.4k
        return value_integer;
3382
37.4k
    }
3383
3384
    /// return unsigned integer value
3385
    constexpr number_unsigned_t get_number_unsigned() const noexcept
3386
314k
    {
3387
314k
        return value_unsigned;
3388
314k
    }
3389
3390
    /// return floating-point value
3391
    constexpr number_float_t get_number_float() const noexcept
3392
234k
    {
3393
234k
        return value_float;
3394
234k
    }
3395
3396
    /// return current string value (implicitly resets the token; useful only once)
3397
    string_t& get_string()
3398
1.49M
    {
3399
1.49M
        return token_buffer;
3400
1.49M
    }
3401
3402
    /////////////////////
3403
    // diagnostics
3404
    /////////////////////
3405
3406
    /// return position of last read token
3407
    constexpr std::size_t get_position() const noexcept
3408
8
    {
3409
8
        return chars_read;
3410
8
    }
3411
3412
    /// return the last read token (for errors only).  Will never contain EOF
3413
    /// (an arbitrary value that is not a valid char value, often -1), because
3414
    /// 255 may legitimately occur.  May contain NUL, which should be escaped.
3415
    std::string get_token_string() const
3416
4
    {
3417
4
        // escape control characters
3418
4
        std::string result;
3419
4
        for (const auto c : token_string)
3420
0
        {
3421
0
            if ('\x00' <= c and c <= '\x1F')
3422
0
            {
3423
0
                // escape control characters
3424
0
                char cs[9];
3425
0
                snprintf(cs, 9, "<U+%.4X>", static_cast<unsigned char>(c));
3426
0
                result += cs;
3427
0
            }
3428
0
            else
3429
0
            {
3430
0
                // add character as is
3431
0
                result.push_back(c);
3432
0
            }
3433
0
        }
3434
4
3435
4
        return result;
3436
4
    }
3437
3438
    /// return syntax error message
3439
    constexpr const char* get_error_message() const noexcept
3440
0
    {
3441
0
        return error_message;
3442
0
    }
3443
3444
    /////////////////////
3445
    // actual scanner
3446
    /////////////////////
3447
3448
    /*!
3449
    @brief skip the UTF-8 byte order mark
3450
    @return true iff there is no BOM or the correct BOM has been skipped
3451
    */
3452
    bool skip_bom()
3453
3.40k
    {
3454
3.40k
        if (get() == 0xEF)
3455
0
        {
3456
0
            if (get() == 0xBB and get() == 0xBF)
3457
0
            {
3458
0
                // we completely parsed the BOM
3459
0
                return true;
3460
0
            }
3461
0
            else
3462
0
            {
3463
0
                // after reading 0xEF, an unexpected character followed
3464
0
                return false;
3465
0
            }
3466
3.40k
        }
3467
3.40k
        else
3468
3.40k
        {
3469
3.40k
            // the first character is not the beginning of the BOM; unget it to
3470
3.40k
            // process is later
3471
3.40k
            unget();
3472
3.40k
            return true;
3473
3.40k
        }
3474
3.40k
    }
3475
3476
    token_type scan()
3477
4.12M
    {
3478
4.12M
        // initially, skip the BOM
3479
4.12M
        if (chars_read == 0 and not skip_bom())
3480
0
        {
3481
0
            error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
3482
0
            return token_type::parse_error;
3483
0
        }
3484
4.12M
3485
4.12M
        // read next character and ignore whitespace
3486
4.12M
        do
3487
4.96M
        {
3488
4.96M
            get();
3489
4.96M
        }
3490
4.96M
        while (current == ' ' or current == '\t' or current == '\n' or current == '\r');
3491
4.12M
3492
4.12M
        switch (current)
3493
4.12M
        {
3494
4.12M
            // structural characters
3495
4.12M
            case '[':
3496
2.45k
                return token_type::begin_array;
3497
4.12M
            case ']':
3498
2.45k
                return token_type::end_array;
3499
4.12M
            case '{':
3500
207k
                return token_type::begin_object;
3501
4.12M
            case '}':
3502
207k
                return token_type::end_object;
3503
4.12M
            case ':':
3504
1.01M
                return token_type::name_separator;
3505
4.12M
            case ',':
3506
840k
                return token_type::value_separator;
3507
4.12M
3508
4.12M
            // literals
3509
4.12M
            case 't':
3510
2.45k
                return scan_literal("true", 4, token_type::literal_true);
3511
4.12M
            case 'f':
3512
0
                return scan_literal("false", 5, token_type::literal_false);
3513
4.12M
            case 'n':
3514
1.64k
                return scan_literal("null", 4, token_type::literal_null);
3515
4.12M
3516
4.12M
            // string
3517
4.12M
            case '\"':
3518
1.26M
                return scan_string();
3519
4.12M
3520
4.12M
            // number
3521
4.12M
            case '-':
3522
586k
            case '0':
3523
586k
            case '1':
3524
586k
            case '2':
3525
586k
            case '3':
3526
586k
            case '4':
3527
586k
            case '5':
3528
586k
            case '6':
3529
586k
            case '7':
3530
586k
            case '8':
3531
586k
            case '9':
3532
586k
                return scan_number();
3533
586k
3534
586k
            // end of input (the null byte is needed when parsing from
3535
586k
            // string literals)
3536
586k
            case '\0':
3537
2.60k
            case std::char_traits<char>::eof():
3538
2.60k
                return token_type::end_of_input;
3539
2.60k
3540
2.60k
            // error
3541
2.60k
            default:
3542
0
                error_message = "invalid literal";
3543
0
                return token_type::parse_error;
3544
0
        }
3545
0
    }
3546
3547
  private:
3548
    /// input adapter
3549
    detail::input_adapter_t ia = nullptr;
3550
3551
    /// the current character
3552
    std::char_traits<char>::int_type current = std::char_traits<char>::eof();
3553
3554
    /// whether the next get() call should just return current
3555
    bool next_unget = false;
3556
3557
    /// the number of characters read
3558
    std::size_t chars_read = 0;
3559
3560
    /// raw input token string (for error messages)
3561
    std::vector<char> token_string {};
3562
3563
    /// buffer for variable-length tokens (numbers, strings)
3564
    string_t token_buffer {};
3565
3566
    /// a description of occurred lexer errors
3567
    const char* error_message = "";
3568
3569
    // number values
3570
    number_integer_t value_integer = 0;
3571
    number_unsigned_t value_unsigned = 0;
3572
    number_float_t value_float = 0;
3573
3574
    /// the decimal point
3575
    const char decimal_point_char = '.';
3576
};
3577
}
3578
}
3579
3580
// #include <nlohmann/detail/input/parser.hpp>
3581
3582
3583
#include <cassert> // assert
3584
#include <cmath> // isfinite
3585
#include <cstdint> // uint8_t
3586
#include <functional> // function
3587
#include <string> // string
3588
#include <utility> // move
3589
3590
// #include <nlohmann/detail/exceptions.hpp>
3591
3592
// #include <nlohmann/detail/macro_scope.hpp>
3593
3594
// #include <nlohmann/detail/meta/is_sax.hpp>
3595
3596
3597
#include <cstdint> // size_t
3598
#include <utility> // declval
3599
3600
// #include <nlohmann/detail/meta/detected.hpp>
3601
3602
// #include <nlohmann/detail/meta/type_traits.hpp>
3603
3604
3605
namespace nlohmann
3606
{
3607
namespace detail
3608
{
3609
template <typename T>
3610
using null_function_t = decltype(std::declval<T&>().null());
3611
3612
template <typename T>
3613
using boolean_function_t =
3614
    decltype(std::declval<T&>().boolean(std::declval<bool>()));
3615
3616
template <typename T, typename Integer>
3617
using number_integer_function_t =
3618
    decltype(std::declval<T&>().number_integer(std::declval<Integer>()));
3619
3620
template <typename T, typename Unsigned>
3621
using number_unsigned_function_t =
3622
    decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));
3623
3624
template <typename T, typename Float, typename String>
3625
using number_float_function_t = decltype(std::declval<T&>().number_float(
3626
                                    std::declval<Float>(), std::declval<const String&>()));
3627
3628
template <typename T, typename String>
3629
using string_function_t =
3630
    decltype(std::declval<T&>().string(std::declval<String&>()));
3631
3632
template <typename T>
3633
using start_object_function_t =
3634
    decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));
3635
3636
template <typename T, typename String>
3637
using key_function_t =
3638
    decltype(std::declval<T&>().key(std::declval<String&>()));
3639
3640
template <typename T>
3641
using end_object_function_t = decltype(std::declval<T&>().end_object());
3642
3643
template <typename T>
3644
using start_array_function_t =
3645
    decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));
3646
3647
template <typename T>
3648
using end_array_function_t = decltype(std::declval<T&>().end_array());
3649
3650
template <typename T, typename Exception>
3651
using parse_error_function_t = decltype(std::declval<T&>().parse_error(
3652
        std::declval<std::size_t>(), std::declval<const std::string&>(),
3653
        std::declval<const Exception&>()));
3654
3655
template <typename SAX, typename BasicJsonType>
3656
struct is_sax
3657
{
3658
  private:
3659
    static_assert(is_basic_json<BasicJsonType>::value,
3660
                  "BasicJsonType must be of type basic_json<...>");
3661
3662
    using number_integer_t = typename BasicJsonType::number_integer_t;
3663
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
3664
    using number_float_t = typename BasicJsonType::number_float_t;
3665
    using string_t = typename BasicJsonType::string_t;
3666
    using exception_t = typename BasicJsonType::exception;
3667
3668
  public:
3669
    static constexpr bool value =
3670
        is_detected_exact<bool, null_function_t, SAX>::value &&
3671
        is_detected_exact<bool, boolean_function_t, SAX>::value &&
3672
        is_detected_exact<bool, number_integer_function_t, SAX,
3673
        number_integer_t>::value &&
3674
        is_detected_exact<bool, number_unsigned_function_t, SAX,
3675
        number_unsigned_t>::value &&
3676
        is_detected_exact<bool, number_float_function_t, SAX, number_float_t,
3677
        string_t>::value &&
3678
        is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
3679
        is_detected_exact<bool, start_object_function_t, SAX>::value &&
3680
        is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
3681
        is_detected_exact<bool, end_object_function_t, SAX>::value &&
3682
        is_detected_exact<bool, start_array_function_t, SAX>::value &&
3683
        is_detected_exact<bool, end_array_function_t, SAX>::value &&
3684
        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
3685
};
3686
3687
template <typename SAX, typename BasicJsonType>
3688
struct is_sax_static_asserts
3689
{
3690
  private:
3691
    static_assert(is_basic_json<BasicJsonType>::value,
3692
                  "BasicJsonType must be of type basic_json<...>");
3693
3694
    using number_integer_t = typename BasicJsonType::number_integer_t;
3695
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
3696
    using number_float_t = typename BasicJsonType::number_float_t;
3697
    using string_t = typename BasicJsonType::string_t;
3698
    using exception_t = typename BasicJsonType::exception;
3699
3700
  public:
3701
    static_assert(is_detected_exact<bool, null_function_t, SAX>::value,
3702
                  "Missing/invalid function: bool null()");
3703
    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
3704
                  "Missing/invalid function: bool boolean(bool)");
3705
    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
3706
                  "Missing/invalid function: bool boolean(bool)");
3707
    static_assert(
3708
        is_detected_exact<bool, number_integer_function_t, SAX,
3709
        number_integer_t>::value,
3710
        "Missing/invalid function: bool number_integer(number_integer_t)");
3711
    static_assert(
3712
        is_detected_exact<bool, number_unsigned_function_t, SAX,
3713
        number_unsigned_t>::value,
3714
        "Missing/invalid function: bool number_unsigned(number_unsigned_t)");
3715
    static_assert(is_detected_exact<bool, number_float_function_t, SAX,
3716
                  number_float_t, string_t>::value,
3717
                  "Missing/invalid function: bool number_float(number_float_t, const string_t&)");
3718
    static_assert(
3719
        is_detected_exact<bool, string_function_t, SAX, string_t>::value,
3720
        "Missing/invalid function: bool string(string_t&)");
3721
    static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,
3722
                  "Missing/invalid function: bool start_object(std::size_t)");
3723
    static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,
3724
                  "Missing/invalid function: bool key(string_t&)");
3725
    static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,
3726
                  "Missing/invalid function: bool end_object()");
3727
    static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,
3728
                  "Missing/invalid function: bool start_array(std::size_t)");
3729
    static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,
3730
                  "Missing/invalid function: bool end_array()");
3731
    static_assert(
3732
        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,
3733
        "Missing/invalid function: bool parse_error(std::size_t, const "
3734
        "std::string&, const exception&)");
3735
};
3736
}
3737
}
3738
3739
// #include <nlohmann/detail/input/input_adapters.hpp>
3740
3741
// #include <nlohmann/detail/input/json_sax.hpp>
3742
3743
3744
#include <cstddef>
3745
#include <string>
3746
#include <vector>
3747
3748
// #include <nlohmann/detail/input/parser.hpp>
3749
3750
// #include <nlohmann/detail/exceptions.hpp>
3751
3752
3753
namespace nlohmann
3754
{
3755
3756
/*!
3757
@brief SAX interface
3758
3759
This class describes the SAX interface used by @ref nlohmann::json::sax_parse.
3760
Each function is called in different situations while the input is parsed. The
3761
boolean return value informs the parser whether to continue processing the
3762
input.
3763
*/
3764
template<typename BasicJsonType>
3765
struct json_sax
3766
{
3767
    /// type for (signed) integers
3768
    using number_integer_t = typename BasicJsonType::number_integer_t;
3769
    /// type for unsigned integers
3770
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
3771
    /// type for floating-point numbers
3772
    using number_float_t = typename BasicJsonType::number_float_t;
3773
    /// type for strings
3774
    using string_t = typename BasicJsonType::string_t;
3775
3776
    /*!
3777
    @brief a null value was read
3778
    @return whether parsing should proceed
3779
    */
3780
    virtual bool null() = 0;
3781
3782
    /*!
3783
    @brief a boolean value was read
3784
    @param[in] val  boolean value
3785
    @return whether parsing should proceed
3786
    */
3787
    virtual bool boolean(bool val) = 0;
3788
3789
    /*!
3790
    @brief an integer number was read
3791
    @param[in] val  integer value
3792
    @return whether parsing should proceed
3793
    */
3794
    virtual bool number_integer(number_integer_t val) = 0;
3795
3796
    /*!
3797
    @brief an unsigned integer number was read
3798
    @param[in] val  unsigned integer value
3799
    @return whether parsing should proceed
3800
    */
3801
    virtual bool number_unsigned(number_unsigned_t val) = 0;
3802
3803
    /*!
3804
    @brief an floating-point number was read
3805
    @param[in] val  floating-point value
3806
    @param[in] s    raw token value
3807
    @return whether parsing should proceed
3808
    */
3809
    virtual bool number_float(number_float_t val, const string_t& s) = 0;
3810
3811
    /*!
3812
    @brief a string was read
3813
    @param[in] val  string value
3814
    @return whether parsing should proceed
3815
    @note It is safe to move the passed string.
3816
    */
3817
    virtual bool string(string_t& val) = 0;
3818
3819
    /*!
3820
    @brief the beginning of an object was read
3821
    @param[in] elements  number of object elements or -1 if unknown
3822
    @return whether parsing should proceed
3823
    @note binary formats may report the number of elements
3824
    */
3825
    virtual bool start_object(std::size_t elements) = 0;
3826
3827
    /*!
3828
    @brief an object key was read
3829
    @param[in] val  object key
3830
    @return whether parsing should proceed
3831
    @note It is safe to move the passed string.
3832
    */
3833
    virtual bool key(string_t& val) = 0;
3834
3835
    /*!
3836
    @brief the end of an object was read
3837
    @return whether parsing should proceed
3838
    */
3839
    virtual bool end_object() = 0;
3840
3841
    /*!
3842
    @brief the beginning of an array was read
3843
    @param[in] elements  number of array elements or -1 if unknown
3844
    @return whether parsing should proceed
3845
    @note binary formats may report the number of elements
3846
    */
3847
    virtual bool start_array(std::size_t elements) = 0;
3848
3849
    /*!
3850
    @brief the end of an array was read
3851
    @return whether parsing should proceed
3852
    */
3853
    virtual bool end_array() = 0;
3854
3855
    /*!
3856
    @brief a parse error occurred
3857
    @param[in] position    the position in the input where the error occurs
3858
    @param[in] last_token  the last read token
3859
    @param[in] error_msg   a detailed error message
3860
    @return whether parsing should proceed (must return false)
3861
    */
3862
    virtual bool parse_error(std::size_t position,
3863
                             const std::string& last_token,
3864
                             const detail::exception& ex) = 0;
3865
3866
    virtual ~json_sax() = default;
3867
};
3868
3869
3870
namespace detail
3871
{
3872
/*!
3873
@brief SAX implementation to create a JSON value from SAX events
3874
3875
This class implements the @ref json_sax interface and processes the SAX events
3876
to create a JSON value which makes it basically a DOM parser. The structure or
3877
hierarchy of the JSON value is managed by the stack `ref_stack` which contains
3878
a pointer to the respective array or object for each recursion depth.
3879
3880
After successful parsing, the value that is passed by reference to the
3881
constructor contains the parsed value.
3882
3883
@tparam BasicJsonType  the JSON type
3884
*/
3885
template<typename BasicJsonType>
3886
class json_sax_dom_parser
3887
{
3888
  public:
3889
    using number_integer_t = typename BasicJsonType::number_integer_t;
3890
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
3891
    using number_float_t = typename BasicJsonType::number_float_t;
3892
    using string_t = typename BasicJsonType::string_t;
3893
3894
    /*!
3895
    @param[in, out] r  reference to a JSON value that is manipulated while
3896
                       parsing
3897
    @param[in] allow_exceptions_  whether parse errors yield exceptions
3898
    */
3899
    explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)
3900
        : root(r), allow_exceptions(allow_exceptions_)
3901
3.40k
    {}
3902
3903
    bool null()
3904
1.64k
    {
3905
1.64k
        handle_value(nullptr);
3906
1.64k
        return true;
3907
1.64k
    }
3908
3909
    bool boolean(bool val)
3910
2.45k
    {
3911
2.45k
        handle_value(val);
3912
2.45k
        return true;
3913
2.45k
    }
3914
3915
    bool number_integer(number_integer_t val)
3916
37.4k
    {
3917
37.4k
        handle_value(val);
3918
37.4k
        return true;
3919
37.4k
    }
3920
3921
    bool number_unsigned(number_unsigned_t val)
3922
314k
    {
3923
314k
        handle_value(val);
3924
314k
        return true;
3925
314k
    }
3926
3927
    bool number_float(number_float_t val, const string_t&)
3928
234k
    {
3929
234k
        handle_value(val);
3930
234k
        return true;
3931
234k
    }
3932
3933
    bool string(string_t& val)
3934
252k
    {
3935
252k
        handle_value(val);
3936
252k
        return true;
3937
252k
    }
3938
3939
    bool start_object(std::size_t len)
3940
207k
    {
3941
207k
        ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
3942
207k
3943
207k
        if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
3944
207k
        {
3945
0
            JSON_THROW(out_of_range::create(408,
3946
0
                                            "excessive object size: " + std::to_string(len)));
3947
0
        }
3948
207k
3949
207k
        return true;
3950
207k
    }
3951
3952
    bool key(string_t& val)
3953
1.01M
    {
3954
1.01M
        // add null at given key and store the reference for later
3955
1.01M
        object_element = &(ref_stack.back()->m_value.object->operator[](val));
3956
1.01M
        return true;
3957
1.01M
    }
3958
3959
    bool end_object()
3960
207k
    {
3961
207k
        ref_stack.pop_back();
3962
207k
        return true;
3963
207k
    }
3964
3965
    bool start_array(std::size_t len)
3966
2.45k
    {
3967
2.45k
        ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
3968
2.45k
3969
2.45k
        if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
3970
2.45k
        {
3971
0
            JSON_THROW(out_of_range::create(408,
3972
0
                                            "excessive array size: " + std::to_string(len)));
3973
0
        }
3974
2.45k
3975
2.45k
        return true;
3976
2.45k
    }
3977
3978
    bool end_array()
3979
2.45k
    {
3980
2.45k
        ref_stack.pop_back();
3981
2.45k
        return true;
3982
2.45k
    }
3983
3984
    bool parse_error(std::size_t, const std::string&,
3985
                     const detail::exception& ex)
3986
4
    {
3987
4
        errored = true;
3988
4
        if (allow_exceptions)
3989
4
        {
3990
4
            // determine the proper exception type from the id
3991
4
            switch ((ex.id / 100) % 100)
3992
4
            {
3993
4
                case 1:
3994
4
                    JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex));
3995
4
                case 4:
3996
0
                    JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex));
3997
4
                // LCOV_EXCL_START
3998
4
                case 2:
3999
0
                    JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex));
4000
4
                case 3:
4001
0
                    JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex));
4002
4
                case 5:
4003
0
                    JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex));
4004
4
                default:
4005
0
                    assert(false);
4006
4
                    // LCOV_EXCL_STOP
4007
4
            }
4008
4
        }
4009
4
        return false;
4010
4
    }
4011
4012
    constexpr bool is_errored() const
4013
3.40k
    {
4014
3.40k
        return errored;
4015
3.40k
    }
4016
4017
  private:
4018
    /*!
4019
    @invariant If the ref stack is empty, then the passed value will be the new
4020
               root.
4021
    @invariant If the ref stack contains a value, then it is an array or an
4022
               object to which we can add elements
4023
    */
4024
    template<typename Value>
4025
    BasicJsonType* handle_value(Value&& v)
4026
1.05M
    {
4027
1.05M
        if (ref_stack.empty())
4028
3.40k
        {
4029
3.40k
            root = BasicJsonType(std::forward<Value>(v));
4030
3.40k
            return &root;
4031
3.40k
        }
4032
1.04M
        else
4033
1.04M
        {
4034
1.04M
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
4035
1.04M
            if (ref_stack.back()->is_array())
4036
39.0k
            {
4037
39.0k
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
4038
39.0k
                return &(ref_stack.back()->m_value.array->back());
4039
39.0k
            }
4040
1.01M
            else
4041
1.01M
            {
4042
1.01M
                assert(object_element);
4043
1.01M
                *object_element = BasicJsonType(std::forward<Value>(v));
4044
1.01M
                return object_element;
4045
1.01M
            }
4046
0
        }
4047
0
    }
_ZN8nlohmann6detail19json_sax_dom_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueINS0_7value_tEEEPSC_OT_
Line
Count
Source
4026
210k
    {
4027
210k
        if (ref_stack.empty())
4028
3.40k
        {
4029
3.40k
            root = BasicJsonType(std::forward<Value>(v));
4030
3.40k
            return &root;
4031
3.40k
        }
4032
206k
        else
4033
206k
        {
4034
206k
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
4035
206k
            if (ref_stack.back()->is_array())
4036
39.0k
            {
4037
39.0k
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
4038
39.0k
                return &(ref_stack.back()->m_value.array->back());
4039
39.0k
            }
4040
167k
            else
4041
167k
            {
4042
167k
                assert(object_element);
4043
167k
                *object_element = BasicJsonType(std::forward<Value>(v));
4044
167k
                return object_element;
4045
167k
            }
4046
0
        }
4047
0
    }
_ZN8nlohmann6detail19json_sax_dom_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRdEEPSC_OT_
Line
Count
Source
4026
234k
    {
4027
234k
        if (ref_stack.empty())
4028
0
        {
4029
0
            root = BasicJsonType(std::forward<Value>(v));
4030
0
            return &root;
4031
0
        }
4032
234k
        else
4033
234k
        {
4034
234k
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
4035
234k
            if (ref_stack.back()->is_array())
4036
0
            {
4037
0
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
4038
0
                return &(ref_stack.back()->m_value.array->back());
4039
0
            }
4040
234k
            else
4041
234k
            {
4042
234k
                assert(object_element);
4043
234k
                *object_element = BasicJsonType(std::forward<Value>(v));
4044
234k
                return object_element;
4045
234k
            }
4046
0
        }
4047
0
    }
_ZN8nlohmann6detail19json_sax_dom_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRbEEPSC_OT_
Line
Count
Source
4026
2.45k
    {
4027
2.45k
        if (ref_stack.empty())
4028
0
        {
4029
0
            root = BasicJsonType(std::forward<Value>(v));
4030
0
            return &root;
4031
0
        }
4032
2.45k
        else
4033
2.45k
        {
4034
2.45k
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
4035
2.45k
            if (ref_stack.back()->is_array())
4036
0
            {
4037
0
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
4038
0
                return &(ref_stack.back()->m_value.array->back());
4039
0
            }
4040
2.45k
            else
4041
2.45k
            {
4042
2.45k
                assert(object_element);
4043
2.45k
                *object_element = BasicJsonType(std::forward<Value>(v));
4044
2.45k
                return object_element;
4045
2.45k
            }
4046
0
        }
4047
0
    }
_ZN8nlohmann6detail19json_sax_dom_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIDnEEPSC_OT_
Line
Count
Source
4026
1.64k
    {
4027
1.64k
        if (ref_stack.empty())
4028
0
        {
4029
0
            root = BasicJsonType(std::forward<Value>(v));
4030
0
            return &root;
4031
0
        }
4032
1.64k
        else
4033
1.64k
        {
4034
1.64k
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
4035
1.64k
            if (ref_stack.back()->is_array())
4036
0
            {
4037
0
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
4038
0
                return &(ref_stack.back()->m_value.array->back());
4039
0
            }
4040
1.64k
            else
4041
1.64k
            {
4042
1.64k
                assert(object_element);
4043
1.64k
                *object_element = BasicJsonType(std::forward<Value>(v));
4044
1.64k
                return object_element;
4045
1.64k
            }
4046
0
        }
4047
0
    }
_ZN8nlohmann6detail19json_sax_dom_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRlEEPSC_OT_
Line
Count
Source
4026
37.4k
    {
4027
37.4k
        if (ref_stack.empty())
4028
0
        {
4029
0
            root = BasicJsonType(std::forward<Value>(v));
4030
0
            return &root;
4031
0
        }
4032
37.4k
        else
4033
37.4k
        {
4034
37.4k
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
4035
37.4k
            if (ref_stack.back()->is_array())
4036
0
            {
4037
0
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
4038
0
                return &(ref_stack.back()->m_value.array->back());
4039
0
            }
4040
37.4k
            else
4041
37.4k
            {
4042
37.4k
                assert(object_element);
4043
37.4k
                *object_element = BasicJsonType(std::forward<Value>(v));
4044
37.4k
                return object_element;
4045
37.4k
            }
4046
0
        }
4047
0
    }
_ZN8nlohmann6detail19json_sax_dom_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRSA_EEPSC_OT_
Line
Count
Source
4026
252k
    {
4027
252k
        if (ref_stack.empty())
4028
0
        {
4029
0
            root = BasicJsonType(std::forward<Value>(v));
4030
0
            return &root;
4031
0
        }
4032
252k
        else
4033
252k
        {
4034
252k
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
4035
252k
            if (ref_stack.back()->is_array())
4036
0
            {
4037
0
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
4038
0
                return &(ref_stack.back()->m_value.array->back());
4039
0
            }
4040
252k
            else
4041
252k
            {
4042
252k
                assert(object_element);
4043
252k
                *object_element = BasicJsonType(std::forward<Value>(v));
4044
252k
                return object_element;
4045
252k
            }
4046
0
        }
4047
0
    }
_ZN8nlohmann6detail19json_sax_dom_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRmEEPSC_OT_
Line
Count
Source
4026
314k
    {
4027
314k
        if (ref_stack.empty())
4028
0
        {
4029
0
            root = BasicJsonType(std::forward<Value>(v));
4030
0
            return &root;
4031
0
        }
4032
314k
        else
4033
314k
        {
4034
314k
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
4035
314k
            if (ref_stack.back()->is_array())
4036
0
            {
4037
0
                ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
4038
0
                return &(ref_stack.back()->m_value.array->back());
4039
0
            }
4040
314k
            else
4041
314k
            {
4042
314k
                assert(object_element);
4043
314k
                *object_element = BasicJsonType(std::forward<Value>(v));
4044
314k
                return object_element;
4045
314k
            }
4046
0
        }
4047
0
    }
4048
4049
    /// the parsed JSON value
4050
    BasicJsonType& root;
4051
    /// stack to model hierarchy of values
4052
    std::vector<BasicJsonType*> ref_stack;
4053
    /// helper to hold the reference for the next object element
4054
    BasicJsonType* object_element = nullptr;
4055
    /// whether a syntax error occurred
4056
    bool errored = false;
4057
    /// whether to throw exceptions in case of errors
4058
    const bool allow_exceptions = true;
4059
};
4060
4061
template<typename BasicJsonType>
4062
class json_sax_dom_callback_parser
4063
{
4064
  public:
4065
    using number_integer_t = typename BasicJsonType::number_integer_t;
4066
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
4067
    using number_float_t = typename BasicJsonType::number_float_t;
4068
    using string_t = typename BasicJsonType::string_t;
4069
    using parser_callback_t = typename BasicJsonType::parser_callback_t;
4070
    using parse_event_t = typename BasicJsonType::parse_event_t;
4071
4072
    json_sax_dom_callback_parser(BasicJsonType& r,
4073
                                 const parser_callback_t cb,
4074
                                 const bool allow_exceptions_ = true)
4075
        : root(r), callback(cb), allow_exceptions(allow_exceptions_)
4076
0
    {
4077
0
        keep_stack.push_back(true);
4078
0
    }
4079
4080
    bool null()
4081
0
    {
4082
0
        handle_value(nullptr);
4083
0
        return true;
4084
0
    }
4085
4086
    bool boolean(bool val)
4087
0
    {
4088
0
        handle_value(val);
4089
0
        return true;
4090
0
    }
4091
4092
    bool number_integer(number_integer_t val)
4093
0
    {
4094
0
        handle_value(val);
4095
0
        return true;
4096
0
    }
4097
4098
    bool number_unsigned(number_unsigned_t val)
4099
0
    {
4100
0
        handle_value(val);
4101
0
        return true;
4102
0
    }
4103
4104
    bool number_float(number_float_t val, const string_t&)
4105
0
    {
4106
0
        handle_value(val);
4107
0
        return true;
4108
0
    }
4109
4110
    bool string(string_t& val)
4111
0
    {
4112
0
        handle_value(val);
4113
0
        return true;
4114
0
    }
4115
4116
    bool start_object(std::size_t len)
4117
0
    {
4118
0
        // check callback for object start
4119
0
        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);
4120
0
        keep_stack.push_back(keep);
4121
0
4122
0
        auto val = handle_value(BasicJsonType::value_t::object, true);
4123
0
        ref_stack.push_back(val.second);
4124
0
4125
0
        // check object limit
4126
0
        if (ref_stack.back())
4127
0
        {
4128
0
            if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
4129
0
            {
4130
0
                JSON_THROW(out_of_range::create(408,
4131
0
                                                "excessive object size: " + std::to_string(len)));
4132
0
            }
4133
0
        }
4134
0
4135
0
        return true;
4136
0
    }
4137
4138
    bool key(string_t& val)
4139
0
    {
4140
0
        BasicJsonType k = BasicJsonType(val);
4141
0
4142
0
        // check callback for key
4143
0
        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);
4144
0
        key_keep_stack.push_back(keep);
4145
0
4146
0
        // add discarded value at given key and store the reference for later
4147
0
        if (keep and ref_stack.back())
4148
0
        {
4149
0
            object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);
4150
0
        }
4151
0
4152
0
        return true;
4153
0
    }
4154
4155
    bool end_object()
4156
0
    {
4157
0
        if (ref_stack.back())
4158
0
        {
4159
0
            if (not callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
4160
0
            {
4161
0
                // discard object
4162
0
                *ref_stack.back() = discarded;
4163
0
            }
4164
0
        }
4165
0
4166
0
        assert(not ref_stack.empty());
4167
0
        assert(not keep_stack.empty());
4168
0
        ref_stack.pop_back();
4169
0
        keep_stack.pop_back();
4170
0
4171
0
        if (not ref_stack.empty() and ref_stack.back())
4172
0
        {
4173
0
            // remove discarded value
4174
0
            if (ref_stack.back()->is_object())
4175
0
            {
4176
0
                for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
4177
0
                {
4178
0
                    if (it->is_discarded())
4179
0
                    {
4180
0
                        ref_stack.back()->erase(it);
4181
0
                        break;
4182
0
                    }
4183
0
                }
4184
0
            }
4185
0
        }
4186
0
4187
0
        return true;
4188
0
    }
4189
4190
    bool start_array(std::size_t len)
4191
0
    {
4192
0
        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);
4193
0
        keep_stack.push_back(keep);
4194
0
4195
0
        auto val = handle_value(BasicJsonType::value_t::array, true);
4196
0
        ref_stack.push_back(val.second);
4197
0
4198
0
        // check array limit
4199
0
        if (ref_stack.back())
4200
0
        {
4201
0
            if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
4202
0
            {
4203
0
                JSON_THROW(out_of_range::create(408,
4204
0
                                                "excessive array size: " + std::to_string(len)));
4205
0
            }
4206
0
        }
4207
0
4208
0
        return true;
4209
0
    }
4210
4211
    bool end_array()
4212
0
    {
4213
0
        bool keep = true;
4214
0
4215
0
        if (ref_stack.back())
4216
0
        {
4217
0
            keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
4218
0
            if (not keep)
4219
0
            {
4220
0
                // discard array
4221
0
                *ref_stack.back() = discarded;
4222
0
            }
4223
0
        }
4224
0
4225
0
        assert(not ref_stack.empty());
4226
0
        assert(not keep_stack.empty());
4227
0
        ref_stack.pop_back();
4228
0
        keep_stack.pop_back();
4229
0
4230
0
        // remove discarded value
4231
0
        if (not keep and not ref_stack.empty())
4232
0
        {
4233
0
            if (ref_stack.back()->is_array())
4234
0
            {
4235
0
                ref_stack.back()->m_value.array->pop_back();
4236
0
            }
4237
0
        }
4238
0
4239
0
        return true;
4240
0
    }
4241
4242
    bool parse_error(std::size_t, const std::string&,
4243
                     const detail::exception& ex)
4244
0
    {
4245
0
        errored = true;
4246
0
        if (allow_exceptions)
4247
0
        {
4248
0
            // determine the proper exception type from the id
4249
0
            switch ((ex.id / 100) % 100)
4250
0
            {
4251
0
                case 1:
4252
0
                    JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex));
4253
0
                case 4:
4254
0
                    JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex));
4255
0
                // LCOV_EXCL_START
4256
0
                case 2:
4257
0
                    JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex));
4258
0
                case 3:
4259
0
                    JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex));
4260
0
                case 5:
4261
0
                    JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex));
4262
0
                default:
4263
0
                    assert(false);
4264
0
                    // LCOV_EXCL_STOP
4265
0
            }
4266
0
        }
4267
0
        return false;
4268
0
    }
4269
4270
    constexpr bool is_errored() const
4271
0
    {
4272
0
        return errored;
4273
0
    }
4274
4275
  private:
4276
    /*!
4277
    @param[in] v  value to add to the JSON value we build during parsing
4278
    @param[in] skip_callback  whether we should skip calling the callback
4279
               function; this is required after start_array() and
4280
               start_object() SAX events, because otherwise we would call the
4281
               callback function with an empty array or object, respectively.
4282
4283
    @invariant If the ref stack is empty, then the passed value will be the new
4284
               root.
4285
    @invariant If the ref stack contains a value, then it is an array or an
4286
               object to which we can add elements
4287
4288
    @return pair of boolean (whether value should be kept) and pointer (to the
4289
            passed value in the ref_stack hierarchy; nullptr if not kept)
4290
    */
4291
    template<typename Value>
4292
    std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
4293
0
    {
4294
0
        assert(not keep_stack.empty());
4295
0
4296
0
        // do not handle this value if we know it would be added to a discarded
4297
0
        // container
4298
0
        if (not keep_stack.back())
4299
0
        {
4300
0
            return {false, nullptr};
4301
0
        }
4302
0
4303
0
        // create value
4304
0
        auto value = BasicJsonType(std::forward<Value>(v));
4305
0
4306
0
        // check callback
4307
0
        const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
4308
0
4309
0
        // do not handle this value if we just learnt it shall be discarded
4310
0
        if (not keep)
4311
0
        {
4312
0
            return {false, nullptr};
4313
0
        }
4314
0
4315
0
        if (ref_stack.empty())
4316
0
        {
4317
0
            root = std::move(value);
4318
0
            return {true, &root};
4319
0
        }
4320
0
        else
4321
0
        {
4322
0
            // skip this value if we already decided to skip the parent
4323
0
            // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
4324
0
            if (not ref_stack.back())
4325
0
            {
4326
0
                return {false, nullptr};
4327
0
            }
4328
0
4329
0
            assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
4330
0
            if (ref_stack.back()->is_array())
4331
0
            {
4332
0
                ref_stack.back()->m_value.array->push_back(std::move(value));
4333
0
                return {true, &(ref_stack.back()->m_value.array->back())};
4334
0
            }
4335
0
            else
4336
0
            {
4337
0
                // check if we should store an element for the current key
4338
0
                assert(not key_keep_stack.empty());
4339
0
                const bool store_element = key_keep_stack.back();
4340
0
                key_keep_stack.pop_back();
4341
0
4342
0
                if (not store_element)
4343
0
                {
4344
0
                    return {false, nullptr};
4345
0
                }
4346
0
4347
0
                assert(object_element);
4348
0
                *object_element = std::move(value);
4349
0
                return {true, object_element};
4350
0
            }
4351
0
        }
4352
0
    }
Unexecuted instantiation: _ZN8nlohmann6detail28json_sax_dom_callback_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueINS0_7value_tEEESt4pairIbPSC_EOT_b
Unexecuted instantiation: _ZN8nlohmann6detail28json_sax_dom_callback_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRdEESt4pairIbPSC_EOT_b
Unexecuted instantiation: _ZN8nlohmann6detail28json_sax_dom_callback_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRbEESt4pairIbPSC_EOT_b
Unexecuted instantiation: _ZN8nlohmann6detail28json_sax_dom_callback_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIDnEESt4pairIbPSC_EOT_b
Unexecuted instantiation: _ZN8nlohmann6detail28json_sax_dom_callback_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRlEESt4pairIbPSC_EOT_b
Unexecuted instantiation: _ZN8nlohmann6detail28json_sax_dom_callback_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRSA_EESt4pairIbPSC_EOT_b
Unexecuted instantiation: _ZN8nlohmann6detail28json_sax_dom_callback_parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12handle_valueIRmEESt4pairIbPSC_EOT_b
4353
4354
    /// the parsed JSON value
4355
    BasicJsonType& root;
4356
    /// stack to model hierarchy of values
4357
    std::vector<BasicJsonType*> ref_stack;
4358
    /// stack to manage which values to keep
4359
    std::vector<bool> keep_stack;
4360
    /// stack to manage which object keys to keep
4361
    std::vector<bool> key_keep_stack;
4362
    /// helper to hold the reference for the next object element
4363
    BasicJsonType* object_element = nullptr;
4364
    /// whether a syntax error occurred
4365
    bool errored = false;
4366
    /// callback function
4367
    const parser_callback_t callback = nullptr;
4368
    /// whether to throw exceptions in case of errors
4369
    const bool allow_exceptions = true;
4370
    /// a discarded value for the callback
4371
    BasicJsonType discarded = BasicJsonType::value_t::discarded;
4372
};
4373
4374
template<typename BasicJsonType>
4375
class json_sax_acceptor
4376
{
4377
  public:
4378
    using number_integer_t = typename BasicJsonType::number_integer_t;
4379
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
4380
    using number_float_t = typename BasicJsonType::number_float_t;
4381
    using string_t = typename BasicJsonType::string_t;
4382
4383
    bool null()
4384
    {
4385
        return true;
4386
    }
4387
4388
    bool boolean(bool)
4389
    {
4390
        return true;
4391
    }
4392
4393
    bool number_integer(number_integer_t)
4394
    {
4395
        return true;
4396
    }
4397
4398
    bool number_unsigned(number_unsigned_t)
4399
    {
4400
        return true;
4401
    }
4402
4403
    bool number_float(number_float_t, const string_t&)
4404
    {
4405
        return true;
4406
    }
4407
4408
    bool string(string_t&)
4409
    {
4410
        return true;
4411
    }
4412
4413
    bool start_object(std::size_t = std::size_t(-1))
4414
    {
4415
        return true;
4416
    }
4417
4418
    bool key(string_t&)
4419
    {
4420
        return true;
4421
    }
4422
4423
    bool end_object()
4424
    {
4425
        return true;
4426
    }
4427
4428
    bool start_array(std::size_t = std::size_t(-1))
4429
    {
4430
        return true;
4431
    }
4432
4433
    bool end_array()
4434
    {
4435
        return true;
4436
    }
4437
4438
    bool parse_error(std::size_t, const std::string&, const detail::exception&)
4439
    {
4440
        return false;
4441
    }
4442
};
4443
}
4444
4445
}
4446
4447
// #include <nlohmann/detail/input/lexer.hpp>
4448
4449
// #include <nlohmann/detail/value_t.hpp>
4450
4451
4452
namespace nlohmann
4453
{
4454
namespace detail
4455
{
4456
////////////
4457
// parser //
4458
////////////
4459
4460
/*!
4461
@brief syntax analysis
4462
4463
This class implements a recursive decent parser.
4464
*/
4465
template<typename BasicJsonType>
4466
class parser
4467
{
4468
    using number_integer_t = typename BasicJsonType::number_integer_t;
4469
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
4470
    using number_float_t = typename BasicJsonType::number_float_t;
4471
    using string_t = typename BasicJsonType::string_t;
4472
    using lexer_t = lexer<BasicJsonType>;
4473
    using token_type = typename lexer_t::token_type;
4474
4475
  public:
4476
    enum class parse_event_t : uint8_t
4477
    {
4478
        /// the parser read `{` and started to process a JSON object
4479
        object_start,
4480
        /// the parser read `}` and finished processing a JSON object
4481
        object_end,
4482
        /// the parser read `[` and started to process a JSON array
4483
        array_start,
4484
        /// the parser read `]` and finished processing a JSON array
4485
        array_end,
4486
        /// the parser read a key of a value in an object
4487
        key,
4488
        /// the parser finished reading a JSON value
4489
        value
4490
    };
4491
4492
    using parser_callback_t =
4493
        std::function<bool(int depth, parse_event_t event, BasicJsonType& parsed)>;
4494
4495
    /// a parser reading from an input adapter
4496
    explicit parser(detail::input_adapter_t&& adapter,
4497
                    const parser_callback_t cb = nullptr,
4498
                    const bool allow_exceptions_ = true)
4499
        : callback(cb), m_lexer(std::move(adapter)), allow_exceptions(allow_exceptions_)
4500
3.40k
    {
4501
3.40k
        // read first token
4502
3.40k
        get_token();
4503
3.40k
    }
4504
4505
    /*!
4506
    @brief public parser interface
4507
4508
    @param[in] strict      whether to expect the last token to be EOF
4509
    @param[in,out] result  parsed JSON value
4510
4511
    @throw parse_error.101 in case of an unexpected token
4512
    @throw parse_error.102 if to_unicode fails or surrogate error
4513
    @throw parse_error.103 if to_unicode fails
4514
    */
4515
    void parse(const bool strict, BasicJsonType& result)
4516
3.40k
    {
4517
3.40k
        if (callback)
4518
0
        {
4519
0
            json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);
4520
0
            sax_parse_internal(&sdp);
4521
0
            result.assert_invariant();
4522
0
4523
0
            // in strict mode, input must be completely read
4524
0
            if (strict and (get_token() != token_type::end_of_input))
4525
0
            {
4526
0
                sdp.parse_error(m_lexer.get_position(),
4527
0
                                m_lexer.get_token_string(),
4528
0
                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input)));
4529
0
            }
4530
0
4531
0
            // in case of an error, return discarded value
4532
0
            if (sdp.is_errored())
4533
0
            {
4534
0
                result = value_t::discarded;
4535
0
                return;
4536
0
            }
4537
0
4538
0
            // set top-level value to null if it was discarded by the callback
4539
0
            // function
4540
0
            if (result.is_discarded())
4541
0
            {
4542
0
                result = nullptr;
4543
0
            }
4544
0
        }
4545
3.40k
        else
4546
3.40k
        {
4547
3.40k
            json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);
4548
3.40k
            sax_parse_internal(&sdp);
4549
3.40k
            result.assert_invariant();
4550
3.40k
4551
3.40k
            // in strict mode, input must be completely read
4552
3.40k
            if (strict and (get_token() != token_type::end_of_input))
4553
0
            {
4554
0
                sdp.parse_error(m_lexer.get_position(),
4555
0
                                m_lexer.get_token_string(),
4556
0
                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input)));
4557
0
            }
4558
3.40k
4559
3.40k
            // in case of an error, return discarded value
4560
3.40k
            if (sdp.is_errored())
4561
0
            {
4562
0
                result = value_t::discarded;
4563
0
                return;
4564
0
            }
4565
3.40k
        }
4566
3.40k
    }
4567
4568
    /*!
4569
    @brief public accept interface
4570
4571
    @param[in] strict  whether to expect the last token to be EOF
4572
    @return whether the input is a proper JSON text
4573
    */
4574
    bool accept(const bool strict = true)
4575
    {
4576
        json_sax_acceptor<BasicJsonType> sax_acceptor;
4577
        return sax_parse(&sax_acceptor, strict);
4578
    }
4579
4580
    template <typename SAX>
4581
    bool sax_parse(SAX* sax, const bool strict = true)
4582
    {
4583
        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
4584
        const bool result = sax_parse_internal(sax);
4585
4586
        // strict mode: next byte must be EOF
4587
        if (result and strict and (get_token() != token_type::end_of_input))
4588
        {
4589
            return sax->parse_error(m_lexer.get_position(),
4590
                                    m_lexer.get_token_string(),
4591
                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input)));
4592
        }
4593
4594
        return result;
4595
    }
4596
4597
  private:
4598
    template <typename SAX>
4599
    bool sax_parse_internal(SAX* sax)
4600
3.40k
    {
4601
3.40k
        // stack to remember the hieararchy of structured values we are parsing
4602
3.40k
        // true = array; false = object
4603
3.40k
        std::vector<bool> states;
4604
3.40k
        // value to avoid a goto (see comment where set to true)
4605
3.40k
        bool skip_to_state_evaluation = false;
4606
3.40k
4607
1.26M
        while (true)
4608
1.26M
        {
4609
1.26M
            if (not skip_to_state_evaluation)
4610
1.05M
            {
4611
1.05M
                // invariant: get_token() was called before each iteration
4612
1.05M
                switch (last_token)
4613
1.05M
                {
4614
1.05M
                    case token_type::begin_object:
4615
207k
                    {
4616
207k
                        if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))
4617
207k
                        {
4618
0
                            return false;
4619
0
                        }
4620
207k
4621
207k
                        // closing } -> we are done
4622
207k
                        if (get_token() == token_type::end_object)
4623
0
                        {
4624
0
                            if (JSON_UNLIKELY(not sax->end_object()))
4625
0
                            {
4626
0
                                return false;
4627
0
                            }
4628
0
                            break;
4629
0
                        }
4630
207k
4631
207k
                        // parse key
4632
207k
                        if (JSON_UNLIKELY(last_token != token_type::value_string))
4633
207k
                        {
4634
0
                            return sax->parse_error(m_lexer.get_position(),
4635
0
                                                    m_lexer.get_token_string(),
4636
0
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
4637
0
                        }
4638
207k
                        else
4639
207k
                        {
4640
207k
                            if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
4641
207k
                            {
4642
0
                                return false;
4643
0
                            }
4644
207k
                        }
4645
207k
4646
207k
                        // parse separator (:)
4647
207k
                        if (JSON_UNLIKELY(get_token() != token_type::name_separator))
4648
207k
                        {
4649
0
                            return sax->parse_error(m_lexer.get_position(),
4650
0
                                                    m_lexer.get_token_string(),
4651
0
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
4652
0
                        }
4653
207k
4654
207k
                        // remember we are now inside an object
4655
207k
                        states.push_back(false);
4656
207k
4657
207k
                        // parse values
4658
207k
                        get_token();
4659
207k
                        continue;
4660
207k
                    }
4661
207k
4662
207k
                    case token_type::begin_array:
4663
2.45k
                    {
4664
2.45k
                        if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))
4665
2.45k
                        {
4666
0
                            return false;
4667
0
                        }
4668
2.45k
4669
2.45k
                        // closing ] -> we are done
4670
2.45k
                        if (get_token() == token_type::end_array)
4671
812
                        {
4672
812
                            if (JSON_UNLIKELY(not sax->end_array()))
4673
812
                            {
4674
0
                                return false;
4675
0
                            }
4676
812
                            break;
4677
812
                        }
4678
1.64k
4679
1.64k
                        // remember we are now inside an array
4680
1.64k
                        states.push_back(true);
4681
1.64k
4682
1.64k
                        // parse values (no need to call get_token)
4683
1.64k
                        continue;
4684
1.64k
                    }
4685
1.64k
4686
234k
                    case token_type::value_float:
4687
234k
                    {
4688
234k
                        const auto res = m_lexer.get_number_float();
4689
234k
4690
234k
                        if (JSON_UNLIKELY(not std::isfinite(res)))
4691
234k
                        {
4692
0
                            return sax->parse_error(m_lexer.get_position(),
4693
0
                                                    m_lexer.get_token_string(),
4694
0
                                                    out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'"));
4695
0
                        }
4696
234k
                        else
4697
234k
                        {
4698
234k
                            if (JSON_UNLIKELY(not sax->number_float(res, m_lexer.get_string())))
4699
234k
                            {
4700
0
                                return false;
4701
0
                            }
4702
234k
                            break;
4703
234k
                        }
4704
0
                    }
4705
0
4706
0
                    case token_type::literal_false:
4707
0
                    {
4708
0
                        if (JSON_UNLIKELY(not sax->boolean(false)))
4709
0
                        {
4710
0
                            return false;
4711
0
                        }
4712
0
                        break;
4713
0
                    }
4714
0
4715
1.64k
                    case token_type::literal_null:
4716
1.64k
                    {
4717
1.64k
                        if (JSON_UNLIKELY(not sax->null()))
4718
1.64k
                        {
4719
0
                            return false;
4720
0
                        }
4721
1.64k
                        break;
4722
1.64k
                    }
4723
1.64k
4724
2.45k
                    case token_type::literal_true:
4725
2.45k
                    {
4726
2.45k
                        if (JSON_UNLIKELY(not sax->boolean(true)))
4727
2.45k
                        {
4728
0
                            return false;
4729
0
                        }
4730
2.45k
                        break;
4731
2.45k
                    }
4732
2.45k
4733
37.4k
                    case token_type::value_integer:
4734
37.4k
                    {
4735
37.4k
                        if (JSON_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer())))
4736
37.4k
                        {
4737
0
                            return false;
4738
0
                        }
4739
37.4k
                        break;
4740
37.4k
                    }
4741
37.4k
4742
252k
                    case token_type::value_string:
4743
252k
                    {
4744
252k
                        if (JSON_UNLIKELY(not sax->string(m_lexer.get_string())))
4745
252k
                        {
4746
0
                            return false;
4747
0
                        }
4748
252k
                        break;
4749
252k
                    }
4750
252k
4751
314k
                    case token_type::value_unsigned:
4752
314k
                    {
4753
314k
                        if (JSON_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned())))
4754
314k
                        {
4755
0
                            return false;
4756
0
                        }
4757
314k
                        break;
4758
314k
                    }
4759
314k
4760
314k
                    case token_type::parse_error:
4761
0
                    {
4762
0
                        // using "uninitialized" to avoid "expected" message
4763
0
                        return sax->parse_error(m_lexer.get_position(),
4764
0
                                                m_lexer.get_token_string(),
4765
0
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized)));
4766
314k
                    }
4767
314k
4768
314k
                    default: // the last token was unexpected
4769
4
                    {
4770
4
                        return sax->parse_error(m_lexer.get_position(),
4771
4
                                                m_lexer.get_token_string(),
4772
4
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value)));
4773
209k
                    }
4774
209k
                }
4775
209k
            }
4776
209k
            else
4777
209k
            {
4778
209k
                skip_to_state_evaluation = false;
4779
209k
            }
4780
1.26M
4781
1.26M
            // we reached this line after we successfully parsed a value
4782
1.26M
            if (states.empty())
4783
3.40k
            {
4784
3.40k
                // empty stack: we reached the end of the hieararchy: done
4785
3.40k
                return true;
4786
3.40k
            }
4787
1.04M
            else
4788
1.04M
            {
4789
1.04M
                if (states.back())  // array
4790
39.0k
                {
4791
39.0k
                    // comma -> next value
4792
39.0k
                    if (get_token() == token_type::value_separator)
4793
37.4k
                    {
4794
37.4k
                        // parse a new value
4795
37.4k
                        get_token();
4796
37.4k
                        continue;
4797
37.4k
                    }
4798
1.64k
4799
1.64k
                    // closing ]
4800
1.64k
                    if (JSON_LIKELY(last_token == token_type::end_array))
4801
1.64k
                    {
4802
1.64k
                        if (JSON_UNLIKELY(not sax->end_array()))
4803
1.64k
                        {
4804
0
                            return false;
4805
0
                        }
4806
1.64k
4807
1.64k
                        // We are done with this array. Before we can parse a
4808
1.64k
                        // new value, we need to evaluate the new state first.
4809
1.64k
                        // By setting skip_to_state_evaluation to false, we
4810
1.64k
                        // are effectively jumping to the beginning of this if.
4811
1.64k
                        assert(not states.empty());
4812
1.64k
                        states.pop_back();
4813
1.64k
                        skip_to_state_evaluation = true;
4814
1.64k
                        continue;
4815
1.64k
                    }
4816
0
                    else
4817
0
                    {
4818
0
                        return sax->parse_error(m_lexer.get_position(),
4819
0
                                                m_lexer.get_token_string(),
4820
0
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array)));
4821
0
                    }
4822
1.01M
                }
4823
1.01M
                else  // object
4824
1.01M
                {
4825
1.01M
                    // comma -> next value
4826
1.01M
                    if (get_token() == token_type::value_separator)
4827
802k
                    {
4828
802k
                        // parse key
4829
802k
                        if (JSON_UNLIKELY(get_token() != token_type::value_string))
4830
802k
                        {
4831
0
                            return sax->parse_error(m_lexer.get_position(),
4832
0
                                                    m_lexer.get_token_string(),
4833
0
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
4834
0
                        }
4835
802k
                        else
4836
802k
                        {
4837
802k
                            if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
4838
802k
                            {
4839
0
                                return false;
4840
0
                            }
4841
802k
                        }
4842
802k
4843
802k
                        // parse separator (:)
4844
802k
                        if (JSON_UNLIKELY(get_token() != token_type::name_separator))
4845
802k
                        {
4846
0
                            return sax->parse_error(m_lexer.get_position(),
4847
0
                                                    m_lexer.get_token_string(),
4848
0
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
4849
0
                        }
4850
802k
4851
802k
                        // parse values
4852
802k
                        get_token();
4853
802k
                        continue;
4854
802k
                    }
4855
207k
4856
207k
                    // closing }
4857
207k
                    if (JSON_LIKELY(last_token == token_type::end_object))
4858
207k
                    {
4859
207k
                        if (JSON_UNLIKELY(not sax->end_object()))
4860
207k
                        {
4861
0
                            return false;
4862
0
                        }
4863
207k
4864
207k
                        // We are done with this object. Before we can parse a
4865
207k
                        // new value, we need to evaluate the new state first.
4866
207k
                        // By setting skip_to_state_evaluation to false, we
4867
207k
                        // are effectively jumping to the beginning of this if.
4868
207k
                        assert(not states.empty());
4869
207k
                        states.pop_back();
4870
207k
                        skip_to_state_evaluation = true;
4871
207k
                        continue;
4872
207k
                    }
4873
0
                    else
4874
0
                    {
4875
0
                        return sax->parse_error(m_lexer.get_position(),
4876
0
                                                m_lexer.get_token_string(),
4877
0
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object)));
4878
0
                    }
4879
207k
                }
4880
1.04M
            }
4881
1.05M
        }
4882
3.40k
    }
Unexecuted instantiation: _ZN8nlohmann6detail6parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE18sax_parse_internalINS0_28json_sax_dom_callback_parserISC_EEEEbPT_
_ZN8nlohmann6detail6parserINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE18sax_parse_internalINS0_19json_sax_dom_parserISC_EEEEbPT_
Line
Count
Source
4600
3.40k
    {
4601
3.40k
        // stack to remember the hieararchy of structured values we are parsing
4602
3.40k
        // true = array; false = object
4603
3.40k
        std::vector<bool> states;
4604
3.40k
        // value to avoid a goto (see comment where set to true)
4605
3.40k
        bool skip_to_state_evaluation = false;
4606
3.40k
4607
1.26M
        while (true)
4608
1.26M
        {
4609
1.26M
            if (not skip_to_state_evaluation)
4610
1.05M
            {
4611
1.05M
                // invariant: get_token() was called before each iteration
4612
1.05M
                switch (last_token)
4613
1.05M
                {
4614
1.05M
                    case token_type::begin_object:
4615
207k
                    {
4616
207k
                        if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))
4617
207k
                        {
4618
0
                            return false;
4619
0
                        }
4620
207k
4621
207k
                        // closing } -> we are done
4622
207k
                        if (get_token() == token_type::end_object)
4623
0
                        {
4624
0
                            if (JSON_UNLIKELY(not sax->end_object()))
4625
0
                            {
4626
0
                                return false;
4627
0
                            }
4628
0
                            break;
4629
0
                        }
4630
207k
4631
207k
                        // parse key
4632
207k
                        if (JSON_UNLIKELY(last_token != token_type::value_string))
4633
207k
                        {
4634
0
                            return sax->parse_error(m_lexer.get_position(),
4635
0
                                                    m_lexer.get_token_string(),
4636
0
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
4637
0
                        }
4638
207k
                        else
4639
207k
                        {
4640
207k
                            if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
4641
207k
                            {
4642
0
                                return false;
4643
0
                            }
4644
207k
                        }
4645
207k
4646
207k
                        // parse separator (:)
4647
207k
                        if (JSON_UNLIKELY(get_token() != token_type::name_separator))
4648
207k
                        {
4649
0
                            return sax->parse_error(m_lexer.get_position(),
4650
0
                                                    m_lexer.get_token_string(),
4651
0
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
4652
0
                        }
4653
207k
4654
207k
                        // remember we are now inside an object
4655
207k
                        states.push_back(false);
4656
207k
4657
207k
                        // parse values
4658
207k
                        get_token();
4659
207k
                        continue;
4660
207k
                    }
4661
207k
4662
207k
                    case token_type::begin_array:
4663
2.45k
                    {
4664
2.45k
                        if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))
4665
2.45k
                        {
4666
0
                            return false;
4667
0
                        }
4668
2.45k
4669
2.45k
                        // closing ] -> we are done
4670
2.45k
                        if (get_token() == token_type::end_array)
4671
812
                        {
4672
812
                            if (JSON_UNLIKELY(not sax->end_array()))
4673
812
                            {
4674
0
                                return false;
4675
0
                            }
4676
812
                            break;
4677
812
                        }
4678
1.64k
4679
1.64k
                        // remember we are now inside an array
4680
1.64k
                        states.push_back(true);
4681
1.64k
4682
1.64k
                        // parse values (no need to call get_token)
4683
1.64k
                        continue;
4684
1.64k
                    }
4685
1.64k
4686
234k
                    case token_type::value_float:
4687
234k
                    {
4688
234k
                        const auto res = m_lexer.get_number_float();
4689
234k
4690
234k
                        if (JSON_UNLIKELY(not std::isfinite(res)))
4691
234k
                        {
4692
0
                            return sax->parse_error(m_lexer.get_position(),
4693
0
                                                    m_lexer.get_token_string(),
4694
0
                                                    out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'"));
4695
0
                        }
4696
234k
                        else
4697
234k
                        {
4698
234k
                            if (JSON_UNLIKELY(not sax->number_float(res, m_lexer.get_string())))
4699
234k
                            {
4700
0
                                return false;
4701
0
                            }
4702
234k
                            break;
4703
234k
                        }
4704
0
                    }
4705
0
4706
0
                    case token_type::literal_false:
4707
0
                    {
4708
0
                        if (JSON_UNLIKELY(not sax->boolean(false)))
4709
0
                        {
4710
0
                            return false;
4711
0
                        }
4712
0
                        break;
4713
0
                    }
4714
0
4715
1.64k
                    case token_type::literal_null:
4716
1.64k
                    {
4717
1.64k
                        if (JSON_UNLIKELY(not sax->null()))
4718
1.64k
                        {
4719
0
                            return false;
4720
0
                        }
4721
1.64k
                        break;
4722
1.64k
                    }
4723
1.64k
4724
2.45k
                    case token_type::literal_true:
4725
2.45k
                    {
4726
2.45k
                        if (JSON_UNLIKELY(not sax->boolean(true)))
4727
2.45k
                        {
4728
0
                            return false;
4729
0
                        }
4730
2.45k
                        break;
4731
2.45k
                    }
4732
2.45k
4733
37.4k
                    case token_type::value_integer:
4734
37.4k
                    {
4735
37.4k
                        if (JSON_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer())))
4736
37.4k
                        {
4737
0
                            return false;
4738
0
                        }
4739
37.4k
                        break;
4740
37.4k
                    }
4741
37.4k
4742
252k
                    case token_type::value_string:
4743
252k
                    {
4744
252k
                        if (JSON_UNLIKELY(not sax->string(m_lexer.get_string())))
4745
252k
                        {
4746
0
                            return false;
4747
0
                        }
4748
252k
                        break;
4749
252k
                    }
4750
252k
4751
314k
                    case token_type::value_unsigned:
4752
314k
                    {
4753
314k
                        if (JSON_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned())))
4754
314k
                        {
4755
0
                            return false;
4756
0
                        }
4757
314k
                        break;
4758
314k
                    }
4759
314k
4760
314k
                    case token_type::parse_error:
4761
0
                    {
4762
0
                        // using "uninitialized" to avoid "expected" message
4763
0
                        return sax->parse_error(m_lexer.get_position(),
4764
0
                                                m_lexer.get_token_string(),
4765
0
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized)));
4766
314k
                    }
4767
314k
4768
314k
                    default: // the last token was unexpected
4769
4
                    {
4770
4
                        return sax->parse_error(m_lexer.get_position(),
4771
4
                                                m_lexer.get_token_string(),
4772
4
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value)));
4773
209k
                    }
4774
209k
                }
4775
209k
            }
4776
209k
            else
4777
209k
            {
4778
209k
                skip_to_state_evaluation = false;
4779
209k
            }
4780
1.26M
4781
1.26M
            // we reached this line after we successfully parsed a value
4782
1.26M
            if (states.empty())
4783
3.40k
            {
4784
3.40k
                // empty stack: we reached the end of the hieararchy: done
4785
3.40k
                return true;
4786
3.40k
            }
4787
1.04M
            else
4788
1.04M
            {
4789
1.04M
                if (states.back())  // array
4790
39.0k
                {
4791
39.0k
                    // comma -> next value
4792
39.0k
                    if (get_token() == token_type::value_separator)
4793
37.4k
                    {
4794
37.4k
                        // parse a new value
4795
37.4k
                        get_token();
4796
37.4k
                        continue;
4797
37.4k
                    }
4798
1.64k
4799
1.64k
                    // closing ]
4800
1.64k
                    if (JSON_LIKELY(last_token == token_type::end_array))
4801
1.64k
                    {
4802
1.64k
                        if (JSON_UNLIKELY(not sax->end_array()))
4803
1.64k
                        {
4804
0
                            return false;
4805
0
                        }
4806
1.64k
4807
1.64k
                        // We are done with this array. Before we can parse a
4808
1.64k
                        // new value, we need to evaluate the new state first.
4809
1.64k
                        // By setting skip_to_state_evaluation to false, we
4810
1.64k
                        // are effectively jumping to the beginning of this if.
4811
1.64k
                        assert(not states.empty());
4812
1.64k
                        states.pop_back();
4813
1.64k
                        skip_to_state_evaluation = true;
4814
1.64k
                        continue;
4815
1.64k
                    }
4816
0
                    else
4817
0
                    {
4818
0
                        return sax->parse_error(m_lexer.get_position(),
4819
0
                                                m_lexer.get_token_string(),
4820
0
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array)));
4821
0
                    }
4822
1.01M
                }
4823
1.01M
                else  // object
4824
1.01M
                {
4825
1.01M
                    // comma -> next value
4826
1.01M
                    if (get_token() == token_type::value_separator)
4827
802k
                    {
4828
802k
                        // parse key
4829
802k
                        if (JSON_UNLIKELY(get_token() != token_type::value_string))
4830
802k
                        {
4831
0
                            return sax->parse_error(m_lexer.get_position(),
4832
0
                                                    m_lexer.get_token_string(),
4833
0
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
4834
0
                        }
4835
802k
                        else
4836
802k
                        {
4837
802k
                            if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
4838
802k
                            {
4839
0
                                return false;
4840
0
                            }
4841
802k
                        }
4842
802k
4843
802k
                        // parse separator (:)
4844
802k
                        if (JSON_UNLIKELY(get_token() != token_type::name_separator))
4845
802k
                        {
4846
0
                            return sax->parse_error(m_lexer.get_position(),
4847
0
                                                    m_lexer.get_token_string(),
4848
0
                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
4849
0
                        }
4850
802k
4851
802k
                        // parse values
4852
802k
                        get_token();
4853
802k
                        continue;
4854
802k
                    }
4855
207k
4856
207k
                    // closing }
4857
207k
                    if (JSON_LIKELY(last_token == token_type::end_object))
4858
207k
                    {
4859
207k
                        if (JSON_UNLIKELY(not sax->end_object()))
4860
207k
                        {
4861
0
                            return false;
4862
0
                        }
4863
207k
4864
207k
                        // We are done with this object. Before we can parse a
4865
207k
                        // new value, we need to evaluate the new state first.
4866
207k
                        // By setting skip_to_state_evaluation to false, we
4867
207k
                        // are effectively jumping to the beginning of this if.
4868
207k
                        assert(not states.empty());
4869
207k
                        states.pop_back();
4870
207k
                        skip_to_state_evaluation = true;
4871
207k
                        continue;
4872
207k
                    }
4873
0
                    else
4874
0
                    {
4875
0
                        return sax->parse_error(m_lexer.get_position(),
4876
0
                                                m_lexer.get_token_string(),
4877
0
                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object)));
4878
0
                    }
4879
207k
                }
4880
1.04M
            }
4881
1.05M
        }
4882
3.40k
    }
4883
4884
    /// get next token from lexer
4885
    token_type get_token()
4886
4.12M
    {
4887
4.12M
        return (last_token = m_lexer.scan());
4888
4.12M
    }
4889
4890
    std::string exception_message(const token_type expected)
4891
4
    {
4892
4
        std::string error_msg = "syntax error - ";
4893
4
        if (last_token == token_type::parse_error)
4894
0
        {
4895
0
            error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" +
4896
0
                         m_lexer.get_token_string() + "'";
4897
0
        }
4898
4
        else
4899
4
        {
4900
4
            error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token));
4901
4
        }
4902
4
4903
4
        if (expected != token_type::uninitialized)
4904
4
        {
4905
4
            error_msg += "; expected " + std::string(lexer_t::token_type_name(expected));
4906
4
        }
4907
4
4908
4
        return error_msg;
4909
4
    }
4910
4911
  private:
4912
    /// callback function
4913
    const parser_callback_t callback = nullptr;
4914
    /// the type of the last read token
4915
    token_type last_token = token_type::uninitialized;
4916
    /// the lexer
4917
    lexer_t m_lexer;
4918
    /// whether to throw exceptions in case of errors
4919
    const bool allow_exceptions = true;
4920
};
4921
}
4922
}
4923
4924
// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
4925
4926
4927
#include <cstddef> // ptrdiff_t
4928
#include <limits>  // numeric_limits
4929
4930
namespace nlohmann
4931
{
4932
namespace detail
4933
{
4934
/*
4935
@brief an iterator for primitive JSON types
4936
4937
This class models an iterator for primitive JSON types (boolean, number,
4938
string). It's only purpose is to allow the iterator/const_iterator classes
4939
to "iterate" over primitive values. Internally, the iterator is modeled by
4940
a `difference_type` variable. Value begin_value (`0`) models the begin,
4941
end_value (`1`) models past the end.
4942
*/
4943
class primitive_iterator_t
4944
{
4945
  private:
4946
    using difference_type = std::ptrdiff_t;
4947
    static constexpr difference_type begin_value = 0;
4948
    static constexpr difference_type end_value = begin_value + 1;
4949
4950
    /// iterator as signed integer type
4951
    difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();
4952
4953
  public:
4954
    constexpr difference_type get_value() const noexcept
4955
0
    {
4956
0
        return m_it;
4957
0
    }
4958
4959
    /// set iterator to a defined beginning
4960
    void set_begin() noexcept
4961
0
    {
4962
0
        m_it = begin_value;
4963
0
    }
4964
4965
    /// set iterator to a defined past the end
4966
    void set_end() noexcept
4967
8
    {
4968
8
        m_it = end_value;
4969
8
    }
4970
4971
    /// return whether the iterator can be dereferenced
4972
    constexpr bool is_begin() const noexcept
4973
0
    {
4974
0
        return m_it == begin_value;
4975
0
    }
4976
4977
    /// return whether the iterator is at end
4978
    constexpr bool is_end() const noexcept
4979
0
    {
4980
0
        return m_it == end_value;
4981
0
    }
4982
4983
    friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
4984
4
    {
4985
4
        return lhs.m_it == rhs.m_it;
4986
4
    }
4987
4988
    friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
4989
    {
4990
        return lhs.m_it < rhs.m_it;
4991
    }
4992
4993
    primitive_iterator_t operator+(difference_type n) noexcept
4994
0
    {
4995
0
        auto result = *this;
4996
0
        result += n;
4997
0
        return result;
4998
0
    }
4999
5000
    friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
5001
    {
5002
        return lhs.m_it - rhs.m_it;
5003
    }
5004
5005
    primitive_iterator_t& operator++() noexcept
5006
0
    {
5007
0
        ++m_it;
5008
0
        return *this;
5009
0
    }
5010
5011
    primitive_iterator_t const operator++(int) noexcept
5012
0
    {
5013
0
        auto result = *this;
5014
0
        ++m_it;
5015
0
        return result;
5016
0
    }
5017
5018
    primitive_iterator_t& operator--() noexcept
5019
0
    {
5020
0
        --m_it;
5021
0
        return *this;
5022
0
    }
5023
5024
    primitive_iterator_t const operator--(int) noexcept
5025
0
    {
5026
0
        auto result = *this;
5027
0
        --m_it;
5028
0
        return result;
5029
0
    }
5030
5031
    primitive_iterator_t& operator+=(difference_type n) noexcept
5032
0
    {
5033
0
        m_it += n;
5034
0
        return *this;
5035
0
    }
5036
5037
    primitive_iterator_t& operator-=(difference_type n) noexcept
5038
0
    {
5039
0
        m_it -= n;
5040
0
        return *this;
5041
0
    }
5042
};
5043
}
5044
}
5045
5046
// #include <nlohmann/detail/iterators/internal_iterator.hpp>
5047
5048
5049
// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
5050
5051
5052
namespace nlohmann
5053
{
5054
namespace detail
5055
{
5056
/*!
5057
@brief an iterator value
5058
5059
@note This structure could easily be a union, but MSVC currently does not allow
5060
unions members with complex constructors, see https://github.com/nlohmann/json/pull/105.
5061
*/
5062
template<typename BasicJsonType> struct internal_iterator
5063
{
5064
    /// iterator for JSON objects
5065
    typename BasicJsonType::object_t::iterator object_iterator {};
5066
    /// iterator for JSON arrays
5067
    typename BasicJsonType::array_t::iterator array_iterator {};
5068
    /// generic iterator for all other types
5069
    primitive_iterator_t primitive_iterator {};
5070
};
5071
}
5072
}
5073
5074
// #include <nlohmann/detail/iterators/iter_impl.hpp>
5075
5076
5077
#include <ciso646> // not
5078
#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next
5079
#include <type_traits> // conditional, is_const, remove_const
5080
5081
// #include <nlohmann/detail/exceptions.hpp>
5082
5083
// #include <nlohmann/detail/iterators/internal_iterator.hpp>
5084
5085
// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
5086
5087
// #include <nlohmann/detail/macro_scope.hpp>
5088
5089
// #include <nlohmann/detail/meta/cpp_future.hpp>
5090
5091
// #include <nlohmann/detail/value_t.hpp>
5092
5093
5094
namespace nlohmann
5095
{
5096
namespace detail
5097
{
5098
// forward declare, to be able to friend it later on
5099
template<typename IteratorType> class iteration_proxy;
5100
5101
/*!
5102
@brief a template for a bidirectional iterator for the @ref basic_json class
5103
5104
This class implements a both iterators (iterator and const_iterator) for the
5105
@ref basic_json class.
5106
5107
@note An iterator is called *initialized* when a pointer to a JSON value has
5108
      been set (e.g., by a constructor or a copy assignment). If the iterator is
5109
      default-constructed, it is *uninitialized* and most methods are undefined.
5110
      **The library uses assertions to detect calls on uninitialized iterators.**
5111
5112
@requirement The class satisfies the following concept requirements:
5113
-
5114
[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
5115
  The iterator that can be moved can be moved in both directions (i.e.
5116
  incremented and decremented).
5117
5118
@since version 1.0.0, simplified in version 2.0.9, change to bidirectional
5119
       iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
5120
*/
5121
template<typename BasicJsonType>
5122
class iter_impl
5123
{
5124
    /// allow basic_json to access private members
5125
    friend iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
5126
    friend BasicJsonType;
5127
    friend iteration_proxy<iter_impl>;
5128
5129
    using object_t = typename BasicJsonType::object_t;
5130
    using array_t = typename BasicJsonType::array_t;
5131
    // make sure BasicJsonType is basic_json or const basic_json
5132
    static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
5133
                  "iter_impl only accepts (const) basic_json");
5134
5135
  public:
5136
5137
    /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
5138
    /// The C++ Standard has never required user-defined iterators to derive from std::iterator.
5139
    /// A user-defined iterator should provide publicly accessible typedefs named
5140
    /// iterator_category, value_type, difference_type, pointer, and reference.
5141
    /// Note that value_type is required to be non-const, even for constant iterators.
5142
    using iterator_category = std::bidirectional_iterator_tag;
5143
5144
    /// the type of the values when the iterator is dereferenced
5145
    using value_type = typename BasicJsonType::value_type;
5146
    /// a type to represent differences between iterators
5147
    using difference_type = typename BasicJsonType::difference_type;
5148
    /// defines a pointer to the type iterated over (value_type)
5149
    using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,
5150
          typename BasicJsonType::const_pointer,
5151
          typename BasicJsonType::pointer>::type;
5152
    /// defines a reference to the type iterated over (value_type)
5153
    using reference =
5154
        typename std::conditional<std::is_const<BasicJsonType>::value,
5155
        typename BasicJsonType::const_reference,
5156
        typename BasicJsonType::reference>::type;
5157
5158
    /// default constructor
5159
    iter_impl() = default;
5160
5161
    /*!
5162
    @brief constructor for a given JSON instance
5163
    @param[in] object  pointer to a JSON object for this iterator
5164
    @pre object != nullptr
5165
    @post The iterator is initialized; i.e. `m_object != nullptr`.
5166
    */
5167
    explicit iter_impl(pointer object) noexcept : m_object(object)
5168
10.4k
    {
5169
10.4k
        assert(m_object != nullptr);
5170
10.4k
5171
10.4k
        switch (m_object->m_type)
5172
10.4k
        {
5173
10.4k
            case value_t::object:
5174
10.4k
            {
5175
10.4k
                m_it.object_iterator = typename object_t::iterator();
5176
10.4k
                break;
5177
10.4k
            }
5178
10.4k
5179
10.4k
            case value_t::array:
5180
64
            {
5181
64
                m_it.array_iterator = typename array_t::iterator();
5182
64
                break;
5183
10.4k
            }
5184
10.4k
5185
10.4k
            default:
5186
8
            {
5187
8
                m_it.primitive_iterator = primitive_iterator_t();
5188
8
                break;
5189
10.4k
            }
5190
10.4k
        }
5191
10.4k
    }
5192
5193
    /*!
5194
    @note The conventional copy constructor and copy assignment are implicitly
5195
          defined. Combined with the following converting constructor and
5196
          assignment, they support: (1) copy from iterator to iterator, (2)
5197
          copy from const iterator to const iterator, and (3) conversion from
5198
          iterator to const iterator. However conversion from const iterator
5199
          to iterator is not defined.
5200
    */
5201
5202
    /*!
5203
    @brief converting constructor
5204
    @param[in] other  non-const iterator to copy from
5205
    @note It is not checked whether @a other is initialized.
5206
    */
5207
    iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
5208
0
        : m_object(other.m_object), m_it(other.m_it) {}
5209
5210
    /*!
5211
    @brief converting assignment
5212
    @param[in,out] other  non-const iterator to copy from
5213
    @return const/non-const iterator
5214
    @note It is not checked whether @a other is initialized.
5215
    */
5216
    iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
5217
    {
5218
        m_object = other.m_object;
5219
        m_it = other.m_it;
5220
        return *this;
5221
    }
5222
5223
  private:
5224
    /*!
5225
    @brief set the iterator to the first value
5226
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5227
    */
5228
    void set_begin() noexcept
5229
2.40k
    {
5230
2.40k
        assert(m_object != nullptr);
5231
2.40k
5232
2.40k
        switch (m_object->m_type)
5233
2.40k
        {
5234
2.40k
            case value_t::object:
5235
2.37k
            {
5236
2.37k
                m_it.object_iterator = m_object->m_value.object->begin();
5237
2.37k
                break;
5238
2.40k
            }
5239
2.40k
5240
2.40k
            case value_t::array:
5241
32
            {
5242
32
                m_it.array_iterator = m_object->m_value.array->begin();
5243
32
                break;
5244
2.40k
            }
5245
2.40k
5246
2.40k
            case value_t::null:
5247
0
            {
5248
0
                // set to end so begin()==end() is true: null is empty
5249
0
                m_it.primitive_iterator.set_end();
5250
0
                break;
5251
2.40k
            }
5252
2.40k
5253
2.40k
            default:
5254
0
            {
5255
0
                m_it.primitive_iterator.set_begin();
5256
0
                break;
5257
2.40k
            }
5258
2.40k
        }
5259
2.40k
    }
5260
5261
    /*!
5262
    @brief set the iterator past the last value
5263
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5264
    */
5265
    void set_end() noexcept
5266
8.08k
    {
5267
8.08k
        assert(m_object != nullptr);
5268
8.08k
5269
8.08k
        switch (m_object->m_type)
5270
8.08k
        {
5271
8.08k
            case value_t::object:
5272
8.04k
            {
5273
8.04k
                m_it.object_iterator = m_object->m_value.object->end();
5274
8.04k
                break;
5275
8.08k
            }
5276
8.08k
5277
8.08k
            case value_t::array:
5278
32
            {
5279
32
                m_it.array_iterator = m_object->m_value.array->end();
5280
32
                break;
5281
8.08k
            }
5282
8.08k
5283
8.08k
            default:
5284
8
            {
5285
8
                m_it.primitive_iterator.set_end();
5286
8
                break;
5287
8.08k
            }
5288
8.08k
        }
5289
8.08k
    }
5290
5291
  public:
5292
    /*!
5293
    @brief return a reference to the value pointed to by the iterator
5294
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5295
    */
5296
    reference operator*() const
5297
6.16k
    {
5298
6.16k
        assert(m_object != nullptr);
5299
6.16k
5300
6.16k
        switch (m_object->m_type)
5301
6.16k
        {
5302
6.16k
            case value_t::object:
5303
5.58k
            {
5304
5.58k
                assert(m_it.object_iterator != m_object->m_value.object->end());
5305
5.58k
                return m_it.object_iterator->second;
5306
6.16k
            }
5307
6.16k
5308
6.16k
            case value_t::array:
5309
584
            {
5310
584
                assert(m_it.array_iterator != m_object->m_value.array->end());
5311
584
                return *m_it.array_iterator;
5312
6.16k
            }
5313
6.16k
5314
6.16k
            case value_t::null:
5315
0
                JSON_THROW(invalid_iterator::create(214, "cannot get value"));
5316
6.16k
5317
6.16k
            default:
5318
0
            {
5319
0
                if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))
5320
0
                {
5321
0
                    return *m_object;
5322
0
                }
5323
0
5324
0
                JSON_THROW(invalid_iterator::create(214, "cannot get value"));
5325
0
            }
5326
0
        }
5327
0
    }
5328
5329
    /*!
5330
    @brief dereference the iterator
5331
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5332
    */
5333
    pointer operator->() const
5334
0
    {
5335
0
        assert(m_object != nullptr);
5336
0
5337
0
        switch (m_object->m_type)
5338
0
        {
5339
0
            case value_t::object:
5340
0
            {
5341
0
                assert(m_it.object_iterator != m_object->m_value.object->end());
5342
0
                return &(m_it.object_iterator->second);
5343
0
            }
5344
0
5345
0
            case value_t::array:
5346
0
            {
5347
0
                assert(m_it.array_iterator != m_object->m_value.array->end());
5348
0
                return &*m_it.array_iterator;
5349
0
            }
5350
0
5351
0
            default:
5352
0
            {
5353
0
                if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))
5354
0
                {
5355
0
                    return m_object;
5356
0
                }
5357
0
5358
0
                JSON_THROW(invalid_iterator::create(214, "cannot get value"));
5359
0
            }
5360
0
        }
5361
0
    }
5362
5363
    /*!
5364
    @brief post-increment (it++)
5365
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5366
    */
5367
    iter_impl const operator++(int)
5368
    {
5369
        auto result = *this;
5370
        ++(*this);
5371
        return result;
5372
    }
5373
5374
    /*!
5375
    @brief pre-increment (++it)
5376
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5377
    */
5378
    iter_impl& operator++()
5379
6.14k
    {
5380
6.14k
        assert(m_object != nullptr);
5381
6.14k
5382
6.14k
        switch (m_object->m_type)
5383
6.14k
        {
5384
6.14k
            case value_t::object:
5385
5.56k
            {
5386
5.56k
                std::advance(m_it.object_iterator, 1);
5387
5.56k
                break;
5388
6.14k
            }
5389
6.14k
5390
6.14k
            case value_t::array:
5391
584
            {
5392
584
                std::advance(m_it.array_iterator, 1);
5393
584
                break;
5394
6.14k
            }
5395
6.14k
5396
6.14k
            default:
5397
0
            {
5398
0
                ++m_it.primitive_iterator;
5399
0
                break;
5400
6.14k
            }
5401
6.14k
        }
5402
6.14k
5403
6.14k
        return *this;
5404
6.14k
    }
5405
5406
    /*!
5407
    @brief post-decrement (it--)
5408
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5409
    */
5410
    iter_impl const operator--(int)
5411
    {
5412
        auto result = *this;
5413
        --(*this);
5414
        return result;
5415
    }
5416
5417
    /*!
5418
    @brief pre-decrement (--it)
5419
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5420
    */
5421
    iter_impl& operator--()
5422
    {
5423
        assert(m_object != nullptr);
5424
5425
        switch (m_object->m_type)
5426
        {
5427
            case value_t::object:
5428
            {
5429
                std::advance(m_it.object_iterator, -1);
5430
                break;
5431
            }
5432
5433
            case value_t::array:
5434
            {
5435
                std::advance(m_it.array_iterator, -1);
5436
                break;
5437
            }
5438
5439
            default:
5440
            {
5441
                --m_it.primitive_iterator;
5442
                break;
5443
            }
5444
        }
5445
5446
        return *this;
5447
    }
5448
5449
    /*!
5450
    @brief  comparison: equal
5451
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5452
    */
5453
    bool operator==(const iter_impl& other) const
5454
8.61k
    {
5455
8.61k
        // if objects are not the same, the comparison is undefined
5456
8.61k
        if (JSON_UNLIKELY(m_object != other.m_object))
5457
8.61k
        {
5458
0
            JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
5459
0
        }
5460
8.61k
5461
8.61k
        assert(m_object != nullptr);
5462
8.61k
5463
8.61k
        switch (m_object->m_type)
5464
8.61k
        {
5465
8.61k
            case value_t::object:
5466
7.99k
                return (m_it.object_iterator == other.m_it.object_iterator);
5467
8.61k
5468
8.61k
            case value_t::array:
5469
616
                return (m_it.array_iterator == other.m_it.array_iterator);
5470
8.61k
5471
8.61k
            default:
5472
4
                return (m_it.primitive_iterator == other.m_it.primitive_iterator);
5473
0
        }
5474
0
    }
5475
5476
    /*!
5477
    @brief  comparison: not equal
5478
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5479
    */
5480
    bool operator!=(const iter_impl& other) const
5481
8.61k
    {
5482
8.61k
        return not operator==(other);
5483
8.61k
    }
5484
5485
    /*!
5486
    @brief  comparison: smaller
5487
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5488
    */
5489
    bool operator<(const iter_impl& other) const
5490
    {
5491
        // if objects are not the same, the comparison is undefined
5492
        if (JSON_UNLIKELY(m_object != other.m_object))
5493
        {
5494
            JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
5495
        }
5496
5497
        assert(m_object != nullptr);
5498
5499
        switch (m_object->m_type)
5500
        {
5501
            case value_t::object:
5502
                JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators"));
5503
5504
            case value_t::array:
5505
                return (m_it.array_iterator < other.m_it.array_iterator);
5506
5507
            default:
5508
                return (m_it.primitive_iterator < other.m_it.primitive_iterator);
5509
        }
5510
    }
5511
5512
    /*!
5513
    @brief  comparison: less than or equal
5514
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5515
    */
5516
    bool operator<=(const iter_impl& other) const
5517
    {
5518
        return not other.operator < (*this);
5519
    }
5520
5521
    /*!
5522
    @brief  comparison: greater than
5523
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5524
    */
5525
    bool operator>(const iter_impl& other) const
5526
    {
5527
        return not operator<=(other);
5528
    }
5529
5530
    /*!
5531
    @brief  comparison: greater than or equal
5532
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5533
    */
5534
    bool operator>=(const iter_impl& other) const
5535
    {
5536
        return not operator<(other);
5537
    }
5538
5539
    /*!
5540
    @brief  add to iterator
5541
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5542
    */
5543
    iter_impl& operator+=(difference_type i)
5544
    {
5545
        assert(m_object != nullptr);
5546
5547
        switch (m_object->m_type)
5548
        {
5549
            case value_t::object:
5550
                JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
5551
5552
            case value_t::array:
5553
            {
5554
                std::advance(m_it.array_iterator, i);
5555
                break;
5556
            }
5557
5558
            default:
5559
            {
5560
                m_it.primitive_iterator += i;
5561
                break;
5562
            }
5563
        }
5564
5565
        return *this;
5566
    }
5567
5568
    /*!
5569
    @brief  subtract from iterator
5570
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5571
    */
5572
    iter_impl& operator-=(difference_type i)
5573
    {
5574
        return operator+=(-i);
5575
    }
5576
5577
    /*!
5578
    @brief  add to iterator
5579
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5580
    */
5581
    iter_impl operator+(difference_type i) const
5582
    {
5583
        auto result = *this;
5584
        result += i;
5585
        return result;
5586
    }
5587
5588
    /*!
5589
    @brief  addition of distance and iterator
5590
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5591
    */
5592
    friend iter_impl operator+(difference_type i, const iter_impl& it)
5593
    {
5594
        auto result = it;
5595
        result += i;
5596
        return result;
5597
    }
5598
5599
    /*!
5600
    @brief  subtract from iterator
5601
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5602
    */
5603
    iter_impl operator-(difference_type i) const
5604
    {
5605
        auto result = *this;
5606
        result -= i;
5607
        return result;
5608
    }
5609
5610
    /*!
5611
    @brief  return difference
5612
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5613
    */
5614
    difference_type operator-(const iter_impl& other) const
5615
    {
5616
        assert(m_object != nullptr);
5617
5618
        switch (m_object->m_type)
5619
        {
5620
            case value_t::object:
5621
                JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
5622
5623
            case value_t::array:
5624
                return m_it.array_iterator - other.m_it.array_iterator;
5625
5626
            default:
5627
                return m_it.primitive_iterator - other.m_it.primitive_iterator;
5628
        }
5629
    }
5630
5631
    /*!
5632
    @brief  access to successor
5633
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5634
    */
5635
    reference operator[](difference_type n) const
5636
    {
5637
        assert(m_object != nullptr);
5638
5639
        switch (m_object->m_type)
5640
        {
5641
            case value_t::object:
5642
                JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators"));
5643
5644
            case value_t::array:
5645
                return *std::next(m_it.array_iterator, n);
5646
5647
            case value_t::null:
5648
                JSON_THROW(invalid_iterator::create(214, "cannot get value"));
5649
5650
            default:
5651
            {
5652
                if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n))
5653
                {
5654
                    return *m_object;
5655
                }
5656
5657
                JSON_THROW(invalid_iterator::create(214, "cannot get value"));
5658
            }
5659
        }
5660
    }
5661
5662
    /*!
5663
    @brief  return the key of an object iterator
5664
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5665
    */
5666
    const typename object_t::key_type& key() const
5667
0
    {
5668
0
        assert(m_object != nullptr);
5669
0
5670
0
        if (JSON_LIKELY(m_object->is_object()))
5671
0
        {
5672
0
            return m_it.object_iterator->first;
5673
0
        }
5674
0
5675
0
        JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators"));
5676
0
    }
5677
5678
    /*!
5679
    @brief  return the value of an iterator
5680
    @pre The iterator is initialized; i.e. `m_object != nullptr`.
5681
    */
5682
    reference value() const
5683
5.58k
    {
5684
5.58k
        return operator*();
5685
5.58k
    }
5686
5687
  private:
5688
    /// associated JSON instance
5689
    pointer m_object = nullptr;
5690
    /// the actual iterator of the associated instance
5691
    internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it;
5692
};
5693
}
5694
}
5695
5696
// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
5697
5698
// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
5699
5700
5701
#include <cstddef> // ptrdiff_t
5702
#include <iterator> // reverse_iterator
5703
#include <utility> // declval
5704
5705
namespace nlohmann
5706
{
5707
namespace detail
5708
{
5709
//////////////////////
5710
// reverse_iterator //
5711
//////////////////////
5712
5713
/*!
5714
@brief a template for a reverse iterator class
5715
5716
@tparam Base the base iterator type to reverse. Valid types are @ref
5717
iterator (to create @ref reverse_iterator) and @ref const_iterator (to
5718
create @ref const_reverse_iterator).
5719
5720
@requirement The class satisfies the following concept requirements:
5721
-
5722
[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
5723
  The iterator that can be moved can be moved in both directions (i.e.
5724
  incremented and decremented).
5725
- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator):
5726
  It is possible to write to the pointed-to element (only if @a Base is
5727
  @ref iterator).
5728
5729
@since version 1.0.0
5730
*/
5731
template<typename Base>
5732
class json_reverse_iterator : public std::reverse_iterator<Base>
5733
{
5734
  public:
5735
    using difference_type = std::ptrdiff_t;
5736
    /// shortcut to the reverse iterator adapter
5737
    using base_iterator = std::reverse_iterator<Base>;
5738
    /// the reference type for the pointed-to element
5739
    using reference = typename Base::reference;
5740
5741
    /// create reverse iterator from iterator
5742
    explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
5743
        : base_iterator(it) {}
5744
5745
    /// create reverse iterator from base class
5746
    explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}
5747
5748
    /// post-increment (it++)
5749
    json_reverse_iterator const operator++(int)
5750
    {
5751
        return static_cast<json_reverse_iterator>(base_iterator::operator++(1));
5752
    }
5753
5754
    /// pre-increment (++it)
5755
    json_reverse_iterator& operator++()
5756
    {
5757
        return static_cast<json_reverse_iterator&>(base_iterator::operator++());
5758
    }
5759
5760
    /// post-decrement (it--)
5761
    json_reverse_iterator const operator--(int)
5762
    {
5763
        return static_cast<json_reverse_iterator>(base_iterator::operator--(1));
5764
    }
5765
5766
    /// pre-decrement (--it)
5767
    json_reverse_iterator& operator--()
5768
    {
5769
        return static_cast<json_reverse_iterator&>(base_iterator::operator--());
5770
    }
5771
5772
    /// add to iterator
5773
    json_reverse_iterator& operator+=(difference_type i)
5774
    {
5775
        return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));
5776
    }
5777
5778
    /// add to iterator
5779
    json_reverse_iterator operator+(difference_type i) const
5780
    {
5781
        return static_cast<json_reverse_iterator>(base_iterator::operator+(i));
5782
    }
5783
5784
    /// subtract from iterator
5785
    json_reverse_iterator operator-(difference_type i) const
5786
    {
5787
        return static_cast<json_reverse_iterator>(base_iterator::operator-(i));
5788
    }
5789
5790
    /// return difference
5791
    difference_type operator-(const json_reverse_iterator& other) const
5792
    {
5793
        return base_iterator(*this) - base_iterator(other);
5794
    }
5795
5796
    /// access to successor
5797
    reference operator[](difference_type n) const
5798
    {
5799
        return *(this->operator+(n));
5800
    }
5801
5802
    /// return the key of an object iterator
5803
    auto key() const -> decltype(std::declval<Base>().key())
5804
    {
5805
        auto it = --this->base();
5806
        return it.key();
5807
    }
5808
5809
    /// return the value of an iterator
5810
    reference value() const
5811
    {
5812
        auto it = --this->base();
5813
        return it.operator * ();
5814
    }
5815
};
5816
}
5817
}
5818
5819
// #include <nlohmann/detail/output/output_adapters.hpp>
5820
5821
5822
#include <algorithm> // copy
5823
#include <cstddef> // size_t
5824
#include <ios> // streamsize
5825
#include <iterator> // back_inserter
5826
#include <memory> // shared_ptr, make_shared
5827
#include <ostream> // basic_ostream
5828
#include <string> // basic_string
5829
#include <vector> // vector
5830
5831
namespace nlohmann
5832
{
5833
namespace detail
5834
{
5835
/// abstract output adapter interface
5836
template<typename CharType> struct output_adapter_protocol
5837
{
5838
    virtual void write_character(CharType c) = 0;
5839
    virtual void write_characters(const CharType* s, std::size_t length) = 0;
5840
508
    virtual ~output_adapter_protocol() = default;
5841
};
5842
5843
/// a type to simplify interfaces
5844
template<typename CharType>
5845
using output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;
5846
5847
/// output adapter for byte vectors
5848
template<typename CharType>
5849
class output_vector_adapter : public output_adapter_protocol<CharType>
5850
{
5851
  public:
5852
    explicit output_vector_adapter(std::vector<CharType>& vec) : v(vec) {}
5853
5854
    void write_character(CharType c) override
5855
    {
5856
        v.push_back(c);
5857
    }
5858
5859
    void write_characters(const CharType* s, std::size_t length) override
5860
    {
5861
        std::copy(s, s + length, std::back_inserter(v));
5862
    }
5863
5864
  private:
5865
    std::vector<CharType>& v;
5866
};
5867
5868
/// output adapter for output streams
5869
template<typename CharType>
5870
class output_stream_adapter : public output_adapter_protocol<CharType>
5871
{
5872
  public:
5873
436
    explicit output_stream_adapter(std::basic_ostream<CharType>& s) : stream(s) {}
5874
5875
    void write_character(CharType c) override
5876
30.7k
    {
5877
30.7k
        stream.put(c);
5878
30.7k
    }
5879
5880
    void write_characters(const CharType* s, std::size_t length) override
5881
42.6k
    {
5882
42.6k
        stream.write(s, static_cast<std::streamsize>(length));
5883
42.6k
    }
5884
5885
  private:
5886
    std::basic_ostream<CharType>& stream;
5887
};
5888
5889
/// output adapter for basic_string
5890
template<typename CharType, typename StringType = std::basic_string<CharType>>
5891
class output_string_adapter : public output_adapter_protocol<CharType>
5892
{
5893
  public:
5894
72
    explicit output_string_adapter(StringType& s) : str(s) {}
5895
5896
    void write_character(CharType c) override
5897
1.41k
    {
5898
1.41k
        str.push_back(c);
5899
1.41k
    }
5900
5901
    void write_characters(const CharType* s, std::size_t length) override
5902
2.56k
    {
5903
2.56k
        str.append(s, length);
5904
2.56k
    }
5905
5906
  private:
5907
    StringType& str;
5908
};
5909
5910
template<typename CharType, typename StringType = std::basic_string<CharType>>
5911
class output_adapter
5912
{
5913
  public:
5914
    output_adapter(std::vector<CharType>& vec)
5915
        : oa(std::make_shared<output_vector_adapter<CharType>>(vec)) {}
5916
5917
    output_adapter(std::basic_ostream<CharType>& s)
5918
436
        : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
5919
5920
    output_adapter(StringType& s)
5921
72
        : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}
5922
5923
    operator output_adapter_t<CharType>()
5924
508
    {
5925
508
        return oa;
5926
508
    }
5927
5928
  private:
5929
    output_adapter_t<CharType> oa = nullptr;
5930
};
5931
}
5932
}
5933
5934
// #include <nlohmann/detail/input/binary_reader.hpp>
5935
5936
5937
#include <algorithm> // generate_n
5938
#include <array> // array
5939
#include <cassert> // assert
5940
#include <cmath> // ldexp
5941
#include <cstddef> // size_t
5942
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
5943
#include <cstdio> // snprintf
5944
#include <cstring> // memcpy
5945
#include <iterator> // back_inserter
5946
#include <limits> // numeric_limits
5947
#include <string> // char_traits, string
5948
#include <utility> // make_pair, move
5949
5950
// #include <nlohmann/detail/input/input_adapters.hpp>
5951
5952
// #include <nlohmann/detail/input/json_sax.hpp>
5953
5954
// #include <nlohmann/detail/exceptions.hpp>
5955
5956
// #include <nlohmann/detail/macro_scope.hpp>
5957
5958
// #include <nlohmann/detail/meta/is_sax.hpp>
5959
5960
// #include <nlohmann/detail/value_t.hpp>
5961
5962
5963
namespace nlohmann
5964
{
5965
namespace detail
5966
{
5967
///////////////////
5968
// binary reader //
5969
///////////////////
5970
5971
/*!
5972
@brief deserialization of CBOR, MessagePack, and UBJSON values
5973
*/
5974
template<typename BasicJsonType, typename SAX = json_sax_dom_parser<BasicJsonType>>
5975
class binary_reader
5976
{
5977
    using number_integer_t = typename BasicJsonType::number_integer_t;
5978
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
5979
    using number_float_t = typename BasicJsonType::number_float_t;
5980
    using string_t = typename BasicJsonType::string_t;
5981
    using json_sax_t = SAX;
5982
5983
  public:
5984
    /*!
5985
    @brief create a binary reader
5986
5987
    @param[in] adapter  input adapter to read from
5988
    */
5989
    explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter))
5990
    {
5991
        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
5992
        assert(ia);
5993
    }
5994
5995
    /*!
5996
    @param[in] format  the binary format to parse
5997
    @param[in] sax_    a SAX event processor
5998
    @param[in] strict  whether to expect the input to be consumed completed
5999
6000
    @return
6001
    */
6002
    bool sax_parse(const input_format_t format,
6003
                   json_sax_t* sax_,
6004
                   const bool strict = true)
6005
    {
6006
        sax = sax_;
6007
        bool result = false;
6008
6009
        switch (format)
6010
        {
6011
            case input_format_t::cbor:
6012
                result = parse_cbor_internal();
6013
                break;
6014
6015
            case input_format_t::msgpack:
6016
                result = parse_msgpack_internal();
6017
                break;
6018
6019
            case input_format_t::ubjson:
6020
                result = parse_ubjson_internal();
6021
                break;
6022
6023
            // LCOV_EXCL_START
6024
            default:
6025
                assert(false);
6026
                // LCOV_EXCL_STOP
6027
        }
6028
6029
        // strict mode: next byte must be EOF
6030
        if (result and strict)
6031
        {
6032
            if (format == input_format_t::ubjson)
6033
            {
6034
                get_ignore_noop();
6035
            }
6036
            else
6037
            {
6038
                get();
6039
            }
6040
6041
            if (JSON_UNLIKELY(current != std::char_traits<char>::eof()))
6042
            {
6043
                return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read, "expected end of input"));
6044
            }
6045
        }
6046
6047
        return result;
6048
    }
6049
6050
    /*!
6051
    @brief determine system byte order
6052
6053
    @return true if and only if system's byte order is little endian
6054
6055
    @note from http://stackoverflow.com/a/1001328/266378
6056
    */
6057
    static constexpr bool little_endianess(int num = 1) noexcept
6058
    {
6059
        return (*reinterpret_cast<char*>(&num) == 1);
6060
    }
6061
6062
  private:
6063
    /*!
6064
    @param[in] get_char  whether a new character should be retrieved from the
6065
                         input (true, default) or whether the last read
6066
                         character should be considered instead
6067
6068
    @return whether a valid CBOR value was passed to the SAX parser
6069
    */
6070
    bool parse_cbor_internal(const bool get_char = true)
6071
    {
6072
        switch (get_char ? get() : current)
6073
        {
6074
            // EOF
6075
            case std::char_traits<char>::eof():
6076
                return unexpect_eof();
6077
6078
            // Integer 0x00..0x17 (0..23)
6079
            case 0x00:
6080
            case 0x01:
6081
            case 0x02:
6082
            case 0x03:
6083
            case 0x04:
6084
            case 0x05:
6085
            case 0x06:
6086
            case 0x07:
6087
            case 0x08:
6088
            case 0x09:
6089
            case 0x0A:
6090
            case 0x0B:
6091
            case 0x0C:
6092
            case 0x0D:
6093
            case 0x0E:
6094
            case 0x0F:
6095
            case 0x10:
6096
            case 0x11:
6097
            case 0x12:
6098
            case 0x13:
6099
            case 0x14:
6100
            case 0x15:
6101
            case 0x16:
6102
            case 0x17:
6103
                return sax->number_unsigned(static_cast<number_unsigned_t>(current));
6104
6105
            case 0x18: // Unsigned integer (one-byte uint8_t follows)
6106
            {
6107
                uint8_t number;
6108
                return get_number(number) and sax->number_unsigned(number);
6109
            }
6110
6111
            case 0x19: // Unsigned integer (two-byte uint16_t follows)
6112
            {
6113
                uint16_t number;
6114
                return get_number(number) and sax->number_unsigned(number);
6115
            }
6116
6117
            case 0x1A: // Unsigned integer (four-byte uint32_t follows)
6118
            {
6119
                uint32_t number;
6120
                return get_number(number) and sax->number_unsigned(number);
6121
            }
6122
6123
            case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
6124
            {
6125
                uint64_t number;
6126
                return get_number(number) and sax->number_unsigned(number);
6127
            }
6128
6129
            // Negative integer -1-0x00..-1-0x17 (-1..-24)
6130
            case 0x20:
6131
            case 0x21:
6132
            case 0x22:
6133
            case 0x23:
6134
            case 0x24:
6135
            case 0x25:
6136
            case 0x26:
6137
            case 0x27:
6138
            case 0x28:
6139
            case 0x29:
6140
            case 0x2A:
6141
            case 0x2B:
6142
            case 0x2C:
6143
            case 0x2D:
6144
            case 0x2E:
6145
            case 0x2F:
6146
            case 0x30:
6147
            case 0x31:
6148
            case 0x32:
6149
            case 0x33:
6150
            case 0x34:
6151
            case 0x35:
6152
            case 0x36:
6153
            case 0x37:
6154
                return sax->number_integer(static_cast<int8_t>(0x20 - 1 - current));
6155
6156
            case 0x38: // Negative integer (one-byte uint8_t follows)
6157
            {
6158
                uint8_t number;
6159
                return get_number(number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
6160
            }
6161
6162
            case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
6163
            {
6164
                uint16_t number;
6165
                return get_number(number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
6166
            }
6167
6168
            case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
6169
            {
6170
                uint32_t number;
6171
                return get_number(number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
6172
            }
6173
6174
            case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
6175
            {
6176
                uint64_t number;
6177
                return get_number(number) and sax->number_integer(static_cast<number_integer_t>(-1)
6178
                        - static_cast<number_integer_t>(number));
6179
            }
6180
6181
            // UTF-8 string (0x00..0x17 bytes follow)
6182
            case 0x60:
6183
            case 0x61:
6184
            case 0x62:
6185
            case 0x63:
6186
            case 0x64:
6187
            case 0x65:
6188
            case 0x66:
6189
            case 0x67:
6190
            case 0x68:
6191
            case 0x69:
6192
            case 0x6A:
6193
            case 0x6B:
6194
            case 0x6C:
6195
            case 0x6D:
6196
            case 0x6E:
6197
            case 0x6F:
6198
            case 0x70:
6199
            case 0x71:
6200
            case 0x72:
6201
            case 0x73:
6202
            case 0x74:
6203
            case 0x75:
6204
            case 0x76:
6205
            case 0x77:
6206
            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
6207
            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
6208
            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
6209
            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
6210
            case 0x7F: // UTF-8 string (indefinite length)
6211
            {
6212
                string_t s;
6213
                return get_cbor_string(s) and sax->string(s);
6214
            }
6215
6216
            // array (0x00..0x17 data items follow)
6217
            case 0x80:
6218
            case 0x81:
6219
            case 0x82:
6220
            case 0x83:
6221
            case 0x84:
6222
            case 0x85:
6223
            case 0x86:
6224
            case 0x87:
6225
            case 0x88:
6226
            case 0x89:
6227
            case 0x8A:
6228
            case 0x8B:
6229
            case 0x8C:
6230
            case 0x8D:
6231
            case 0x8E:
6232
            case 0x8F:
6233
            case 0x90:
6234
            case 0x91:
6235
            case 0x92:
6236
            case 0x93:
6237
            case 0x94:
6238
            case 0x95:
6239
            case 0x96:
6240
            case 0x97:
6241
                return get_cbor_array(static_cast<std::size_t>(current & 0x1F));
6242
6243
            case 0x98: // array (one-byte uint8_t for n follows)
6244
            {
6245
                uint8_t len;
6246
                return get_number(len) and get_cbor_array(static_cast<std::size_t>(len));
6247
            }
6248
6249
            case 0x99: // array (two-byte uint16_t for n follow)
6250
            {
6251
                uint16_t len;
6252
                return get_number(len) and get_cbor_array(static_cast<std::size_t>(len));
6253
            }
6254
6255
            case 0x9A: // array (four-byte uint32_t for n follow)
6256
            {
6257
                uint32_t len;
6258
                return get_number(len) and get_cbor_array(static_cast<std::size_t>(len));
6259
            }
6260
6261
            case 0x9B: // array (eight-byte uint64_t for n follow)
6262
            {
6263
                uint64_t len;
6264
                return get_number(len) and get_cbor_array(static_cast<std::size_t>(len));
6265
            }
6266
6267
            case 0x9F: // array (indefinite length)
6268
                return get_cbor_array(std::size_t(-1));
6269
6270
            // map (0x00..0x17 pairs of data items follow)
6271
            case 0xA0:
6272
            case 0xA1:
6273
            case 0xA2:
6274
            case 0xA3:
6275
            case 0xA4:
6276
            case 0xA5:
6277
            case 0xA6:
6278
            case 0xA7:
6279
            case 0xA8:
6280
            case 0xA9:
6281
            case 0xAA:
6282
            case 0xAB:
6283
            case 0xAC:
6284
            case 0xAD:
6285
            case 0xAE:
6286
            case 0xAF:
6287
            case 0xB0:
6288
            case 0xB1:
6289
            case 0xB2:
6290
            case 0xB3:
6291
            case 0xB4:
6292
            case 0xB5:
6293
            case 0xB6:
6294
            case 0xB7:
6295
                return get_cbor_object(static_cast<std::size_t>(current & 0x1F));
6296
6297
            case 0xB8: // map (one-byte uint8_t for n follows)
6298
            {
6299
                uint8_t len;
6300
                return get_number(len) and get_cbor_object(static_cast<std::size_t>(len));
6301
            }
6302
6303
            case 0xB9: // map (two-byte uint16_t for n follow)
6304
            {
6305
                uint16_t len;
6306
                return get_number(len) and get_cbor_object(static_cast<std::size_t>(len));
6307
            }
6308
6309
            case 0xBA: // map (four-byte uint32_t for n follow)
6310
            {
6311
                uint32_t len;
6312
                return get_number(len) and get_cbor_object(static_cast<std::size_t>(len));
6313
            }
6314
6315
            case 0xBB: // map (eight-byte uint64_t for n follow)
6316
            {
6317
                uint64_t len;
6318
                return get_number(len) and get_cbor_object(static_cast<std::size_t>(len));
6319
            }
6320
6321
            case 0xBF: // map (indefinite length)
6322
                return get_cbor_object(std::size_t(-1));
6323
6324
            case 0xF4: // false
6325
                return sax->boolean(false);
6326
6327
            case 0xF5: // true
6328
                return sax->boolean(true);
6329
6330
            case 0xF6: // null
6331
                return sax->null();
6332
6333
            case 0xF9: // Half-Precision Float (two-byte IEEE 754)
6334
            {
6335
                const int byte1 = get();
6336
                if (JSON_UNLIKELY(not unexpect_eof()))
6337
                {
6338
                    return false;
6339
                }
6340
                const int byte2 = get();
6341
                if (JSON_UNLIKELY(not unexpect_eof()))
6342
                {
6343
                    return false;
6344
                }
6345
6346
                // code from RFC 7049, Appendix D, Figure 3:
6347
                // As half-precision floating-point numbers were only added
6348
                // to IEEE 754 in 2008, today's programming platforms often
6349
                // still only have limited support for them. It is very
6350
                // easy to include at least decoding support for them even
6351
                // without such support. An example of a small decoder for
6352
                // half-precision floating-point numbers in the C language
6353
                // is shown in Fig. 3.
6354
                const int half = (byte1 << 8) + byte2;
6355
                const double val = [&half]
6356
                {
6357
                    const int exp = (half >> 10) & 0x1F;
6358
                    const int mant = half & 0x3FF;
6359
                    assert(0 <= exp and exp <= 32);
6360
                    assert(0 <= mant and mant <= 1024);
6361
                    switch (exp)
6362
                    {
6363
                        case 0:
6364
                            return std::ldexp(mant, -24);
6365
                        case 31:
6366
                            return (mant == 0)
6367
                            ? std::numeric_limits<double>::infinity()
6368
                            : std::numeric_limits<double>::quiet_NaN();
6369
                        default:
6370
                            return std::ldexp(mant + 1024, exp - 25);
6371
                    }
6372
                }();
6373
                return sax->number_float((half & 0x8000) != 0
6374
                                         ? static_cast<number_float_t>(-val)
6375
                                         : static_cast<number_float_t>(val), "");
6376
            }
6377
6378
            case 0xFA: // Single-Precision Float (four-byte IEEE 754)
6379
            {
6380
                float number;
6381
                return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
6382
            }
6383
6384
            case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
6385
            {
6386
                double number;
6387
                return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
6388
            }
6389
6390
            default: // anything else (0xFF is handled inside the other types)
6391
            {
6392
                auto last_token = get_token_string();
6393
                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + last_token));
6394
            }
6395
        }
6396
    }
6397
6398
    /*!
6399
    @return whether a valid MessagePack value was passed to the SAX parser
6400
    */
6401
    bool parse_msgpack_internal()
6402
    {
6403
        switch (get())
6404
        {
6405
            // EOF
6406
            case std::char_traits<char>::eof():
6407
                return unexpect_eof();
6408
6409
            // positive fixint
6410
            case 0x00:
6411
            case 0x01:
6412
            case 0x02:
6413
            case 0x03:
6414
            case 0x04:
6415
            case 0x05:
6416
            case 0x06:
6417
            case 0x07:
6418
            case 0x08:
6419
            case 0x09:
6420
            case 0x0A:
6421
            case 0x0B:
6422
            case 0x0C:
6423
            case 0x0D:
6424
            case 0x0E:
6425
            case 0x0F:
6426
            case 0x10:
6427
            case 0x11:
6428
            case 0x12:
6429
            case 0x13:
6430
            case 0x14:
6431
            case 0x15:
6432
            case 0x16:
6433
            case 0x17:
6434
            case 0x18:
6435
            case 0x19:
6436
            case 0x1A:
6437
            case 0x1B:
6438
            case 0x1C:
6439
            case 0x1D:
6440
            case 0x1E:
6441
            case 0x1F:
6442
            case 0x20:
6443
            case 0x21:
6444
            case 0x22:
6445
            case 0x23:
6446
            case 0x24:
6447
            case 0x25:
6448
            case 0x26:
6449
            case 0x27:
6450
            case 0x28:
6451
            case 0x29:
6452
            case 0x2A:
6453
            case 0x2B:
6454
            case 0x2C:
6455
            case 0x2D:
6456
            case 0x2E:
6457
            case 0x2F:
6458
            case 0x30:
6459
            case 0x31:
6460
            case 0x32:
6461
            case 0x33:
6462
            case 0x34:
6463
            case 0x35:
6464
            case 0x36:
6465
            case 0x37:
6466
            case 0x38:
6467
            case 0x39:
6468
            case 0x3A:
6469
            case 0x3B:
6470
            case 0x3C:
6471
            case 0x3D:
6472
            case 0x3E:
6473
            case 0x3F:
6474
            case 0x40:
6475
            case 0x41:
6476
            case 0x42:
6477
            case 0x43:
6478
            case 0x44:
6479
            case 0x45:
6480
            case 0x46:
6481
            case 0x47:
6482
            case 0x48:
6483
            case 0x49:
6484
            case 0x4A:
6485
            case 0x4B:
6486
            case 0x4C:
6487
            case 0x4D:
6488
            case 0x4E:
6489
            case 0x4F:
6490
            case 0x50:
6491
            case 0x51:
6492
            case 0x52:
6493
            case 0x53:
6494
            case 0x54:
6495
            case 0x55:
6496
            case 0x56:
6497
            case 0x57:
6498
            case 0x58:
6499
            case 0x59:
6500
            case 0x5A:
6501
            case 0x5B:
6502
            case 0x5C:
6503
            case 0x5D:
6504
            case 0x5E:
6505
            case 0x5F:
6506
            case 0x60:
6507
            case 0x61:
6508
            case 0x62:
6509
            case 0x63:
6510
            case 0x64:
6511
            case 0x65:
6512
            case 0x66:
6513
            case 0x67:
6514
            case 0x68:
6515
            case 0x69:
6516
            case 0x6A:
6517
            case 0x6B:
6518
            case 0x6C:
6519
            case 0x6D:
6520
            case 0x6E:
6521
            case 0x6F:
6522
            case 0x70:
6523
            case 0x71:
6524
            case 0x72:
6525
            case 0x73:
6526
            case 0x74:
6527
            case 0x75:
6528
            case 0x76:
6529
            case 0x77:
6530
            case 0x78:
6531
            case 0x79:
6532
            case 0x7A:
6533
            case 0x7B:
6534
            case 0x7C:
6535
            case 0x7D:
6536
            case 0x7E:
6537
            case 0x7F:
6538
                return sax->number_unsigned(static_cast<number_unsigned_t>(current));
6539
6540
            // fixmap
6541
            case 0x80:
6542
            case 0x81:
6543
            case 0x82:
6544
            case 0x83:
6545
            case 0x84:
6546
            case 0x85:
6547
            case 0x86:
6548
            case 0x87:
6549
            case 0x88:
6550
            case 0x89:
6551
            case 0x8A:
6552
            case 0x8B:
6553
            case 0x8C:
6554
            case 0x8D:
6555
            case 0x8E:
6556
            case 0x8F:
6557
                return get_msgpack_object(static_cast<std::size_t>(current & 0x0F));
6558
6559
            // fixarray
6560
            case 0x90:
6561
            case 0x91:
6562
            case 0x92:
6563
            case 0x93:
6564
            case 0x94:
6565
            case 0x95:
6566
            case 0x96:
6567
            case 0x97:
6568
            case 0x98:
6569
            case 0x99:
6570
            case 0x9A:
6571
            case 0x9B:
6572
            case 0x9C:
6573
            case 0x9D:
6574
            case 0x9E:
6575
            case 0x9F:
6576
                return get_msgpack_array(static_cast<std::size_t>(current & 0x0F));
6577
6578
            // fixstr
6579
            case 0xA0:
6580
            case 0xA1:
6581
            case 0xA2:
6582
            case 0xA3:
6583
            case 0xA4:
6584
            case 0xA5:
6585
            case 0xA6:
6586
            case 0xA7:
6587
            case 0xA8:
6588
            case 0xA9:
6589
            case 0xAA:
6590
            case 0xAB:
6591
            case 0xAC:
6592
            case 0xAD:
6593
            case 0xAE:
6594
            case 0xAF:
6595
            case 0xB0:
6596
            case 0xB1:
6597
            case 0xB2:
6598
            case 0xB3:
6599
            case 0xB4:
6600
            case 0xB5:
6601
            case 0xB6:
6602
            case 0xB7:
6603
            case 0xB8:
6604
            case 0xB9:
6605
            case 0xBA:
6606
            case 0xBB:
6607
            case 0xBC:
6608
            case 0xBD:
6609
            case 0xBE:
6610
            case 0xBF:
6611
            {
6612
                string_t s;
6613
                return get_msgpack_string(s) and sax->string(s);
6614
            }
6615
6616
            case 0xC0: // nil
6617
                return sax->null();
6618
6619
            case 0xC2: // false
6620
                return sax->boolean(false);
6621
6622
            case 0xC3: // true
6623
                return sax->boolean(true);
6624
6625
            case 0xCA: // float 32
6626
            {
6627
                float number;
6628
                return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
6629
            }
6630
6631
            case 0xCB: // float 64
6632
            {
6633
                double number;
6634
                return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
6635
            }
6636
6637
            case 0xCC: // uint 8
6638
            {
6639
                uint8_t number;
6640
                return get_number(number) and sax->number_unsigned(number);
6641
            }
6642
6643
            case 0xCD: // uint 16
6644
            {
6645
                uint16_t number;
6646
                return get_number(number) and sax->number_unsigned(number);
6647
            }
6648
6649
            case 0xCE: // uint 32
6650
            {
6651
                uint32_t number;
6652
                return get_number(number) and sax->number_unsigned(number);
6653
            }
6654
6655
            case 0xCF: // uint 64
6656
            {
6657
                uint64_t number;
6658
                return get_number(number) and sax->number_unsigned(number);
6659
            }
6660
6661
            case 0xD0: // int 8
6662
            {
6663
                int8_t number;
6664
                return get_number(number) and sax->number_integer(number);
6665
            }
6666
6667
            case 0xD1: // int 16
6668
            {
6669
                int16_t number;
6670
                return get_number(number) and sax->number_integer(number);
6671
            }
6672
6673
            case 0xD2: // int 32
6674
            {
6675
                int32_t number;
6676
                return get_number(number) and sax->number_integer(number);
6677
            }
6678
6679
            case 0xD3: // int 64
6680
            {
6681
                int64_t number;
6682
                return get_number(number) and sax->number_integer(number);
6683
            }
6684
6685
            case 0xD9: // str 8
6686
            case 0xDA: // str 16
6687
            case 0xDB: // str 32
6688
            {
6689
                string_t s;
6690
                return get_msgpack_string(s) and sax->string(s);
6691
            }
6692
6693
            case 0xDC: // array 16
6694
            {
6695
                uint16_t len;
6696
                return get_number(len) and get_msgpack_array(static_cast<std::size_t>(len));
6697
            }
6698
6699
            case 0xDD: // array 32
6700
            {
6701
                uint32_t len;
6702
                return get_number(len) and get_msgpack_array(static_cast<std::size_t>(len));
6703
            }
6704
6705
            case 0xDE: // map 16
6706
            {
6707
                uint16_t len;
6708
                return get_number(len) and get_msgpack_object(static_cast<std::size_t>(len));
6709
            }
6710
6711
            case 0xDF: // map 32
6712
            {
6713
                uint32_t len;
6714
                return get_number(len) and get_msgpack_object(static_cast<std::size_t>(len));
6715
            }
6716
6717
            // negative fixint
6718
            case 0xE0:
6719
            case 0xE1:
6720
            case 0xE2:
6721
            case 0xE3:
6722
            case 0xE4:
6723
            case 0xE5:
6724
            case 0xE6:
6725
            case 0xE7:
6726
            case 0xE8:
6727
            case 0xE9:
6728
            case 0xEA:
6729
            case 0xEB:
6730
            case 0xEC:
6731
            case 0xED:
6732
            case 0xEE:
6733
            case 0xEF:
6734
            case 0xF0:
6735
            case 0xF1:
6736
            case 0xF2:
6737
            case 0xF3:
6738
            case 0xF4:
6739
            case 0xF5:
6740
            case 0xF6:
6741
            case 0xF7:
6742
            case 0xF8:
6743
            case 0xF9:
6744
            case 0xFA:
6745
            case 0xFB:
6746
            case 0xFC:
6747
            case 0xFD:
6748
            case 0xFE:
6749
            case 0xFF:
6750
                return sax->number_integer(static_cast<int8_t>(current));
6751
6752
            default: // anything else
6753
            {
6754
                auto last_token = get_token_string();
6755
                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "error reading MessagePack; last byte: 0x" + last_token));
6756
            }
6757
        }
6758
    }
6759
6760
    /*!
6761
    @param[in] get_char  whether a new character should be retrieved from the
6762
                         input (true, default) or whether the last read
6763
                         character should be considered instead
6764
6765
    @return whether a valid UBJSON value was passed to the SAX parser
6766
    */
6767
    bool parse_ubjson_internal(const bool get_char = true)
6768
    {
6769
        return get_ubjson_value(get_char ? get_ignore_noop() : current);
6770
    }
6771
6772
    /*!
6773
    @brief get next character from the input
6774
6775
    This function provides the interface to the used input adapter. It does
6776
    not throw in case the input reached EOF, but returns a -'ve valued
6777
    `std::char_traits<char>::eof()` in that case.
6778
6779
    @return character read from the input
6780
    */
6781
    int get()
6782
    {
6783
        ++chars_read;
6784
        return (current = ia->get_character());
6785
    }
6786
6787
    /*!
6788
    @return character read from the input after ignoring all 'N' entries
6789
    */
6790
    int get_ignore_noop()
6791
    {
6792
        do
6793
        {
6794
            get();
6795
        }
6796
        while (current == 'N');
6797
6798
        return current;
6799
    }
6800
6801
    /*
6802
    @brief read a number from the input
6803
6804
    @tparam NumberType the type of the number
6805
    @param[out] result  number of type @a NumberType
6806
6807
    @return whether conversion completed
6808
6809
    @note This function needs to respect the system's endianess, because
6810
          bytes in CBOR, MessagePack, and UBJSON are stored in network order
6811
          (big endian) and therefore need reordering on little endian systems.
6812
    */
6813
    template<typename NumberType>
6814
    bool get_number(NumberType& result)
6815
    {
6816
        // step 1: read input into array with system's byte order
6817
        std::array<uint8_t, sizeof(NumberType)> vec;
6818
        for (std::size_t i = 0; i < sizeof(NumberType); ++i)
6819
        {
6820
            get();
6821
            if (JSON_UNLIKELY(not unexpect_eof()))
6822
            {
6823
                return false;
6824
            }
6825
6826
            // reverse byte order prior to conversion if necessary
6827
            if (is_little_endian)
6828
            {
6829
                vec[sizeof(NumberType) - i - 1] = static_cast<uint8_t>(current);
6830
            }
6831
            else
6832
            {
6833
                vec[i] = static_cast<uint8_t>(current); // LCOV_EXCL_LINE
6834
            }
6835
        }
6836
6837
        // step 2: convert array into number of type T and return
6838
        std::memcpy(&result, vec.data(), sizeof(NumberType));
6839
        return true;
6840
    }
6841
6842
    /*!
6843
    @brief create a string by reading characters from the input
6844
6845
    @tparam NumberType the type of the number
6846
    @param[in] len number of characters to read
6847
    @param[out] string created by reading @a len bytes
6848
6849
    @return whether string creation completed
6850
6851
    @note We can not reserve @a len bytes for the result, because @a len
6852
          may be too large. Usually, @ref unexpect_eof() detects the end of
6853
          the input before we run out of string memory.
6854
    */
6855
    template<typename NumberType>
6856
    bool get_string(const NumberType len, string_t& result)
6857
    {
6858
        bool success = true;
6859
        std::generate_n(std::back_inserter(result), len, [this, &success]()
6860
        {
6861
            get();
6862
            if (JSON_UNLIKELY(not unexpect_eof()))
6863
            {
6864
                success = false;
6865
            }
6866
            return static_cast<char>(current);
6867
        });
6868
        return success;
6869
    }
6870
6871
    /*!
6872
    @brief reads a CBOR string
6873
6874
    This function first reads starting bytes to determine the expected
6875
    string length and then copies this number of bytes into a string.
6876
    Additionally, CBOR's strings with indefinite lengths are supported.
6877
6878
    @param[out] result  created string
6879
6880
    @return whether string creation completed
6881
    */
6882
    bool get_cbor_string(string_t& result)
6883
    {
6884
        if (JSON_UNLIKELY(not unexpect_eof()))
6885
        {
6886
            return false;
6887
        }
6888
6889
        switch (current)
6890
        {
6891
            // UTF-8 string (0x00..0x17 bytes follow)
6892
            case 0x60:
6893
            case 0x61:
6894
            case 0x62:
6895
            case 0x63:
6896
            case 0x64:
6897
            case 0x65:
6898
            case 0x66:
6899
            case 0x67:
6900
            case 0x68:
6901
            case 0x69:
6902
            case 0x6A:
6903
            case 0x6B:
6904
            case 0x6C:
6905
            case 0x6D:
6906
            case 0x6E:
6907
            case 0x6F:
6908
            case 0x70:
6909
            case 0x71:
6910
            case 0x72:
6911
            case 0x73:
6912
            case 0x74:
6913
            case 0x75:
6914
            case 0x76:
6915
            case 0x77:
6916
            {
6917
                return get_string(current & 0x1F, result);
6918
            }
6919
6920
            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
6921
            {
6922
                uint8_t len;
6923
                return get_number(len) and get_string(len, result);
6924
            }
6925
6926
            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
6927
            {
6928
                uint16_t len;
6929
                return get_number(len) and get_string(len, result);
6930
            }
6931
6932
            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
6933
            {
6934
                uint32_t len;
6935
                return get_number(len) and get_string(len, result);
6936
            }
6937
6938
            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
6939
            {
6940
                uint64_t len;
6941
                return get_number(len) and get_string(len, result);
6942
            }
6943
6944
            case 0x7F: // UTF-8 string (indefinite length)
6945
            {
6946
                while (get() != 0xFF)
6947
                {
6948
                    string_t chunk;
6949
                    if (not get_cbor_string(chunk))
6950
                    {
6951
                        return false;
6952
                    }
6953
                    result.append(chunk);
6954
                }
6955
                return true;
6956
            }
6957
6958
            default:
6959
            {
6960
                auto last_token = get_token_string();
6961
                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + last_token));
6962
            }
6963
        }
6964
    }
6965
6966
    /*!
6967
    @param[in] len  the length of the array or std::size_t(-1) for an
6968
                    array of indefinite size
6969
    @return whether array creation completed
6970
    */
6971
    bool get_cbor_array(const std::size_t len)
6972
    {
6973
        if (JSON_UNLIKELY(not sax->start_array(len)))
6974
        {
6975
            return false;
6976
        }
6977
6978
        if (len != std::size_t(-1))
6979
            for (std::size_t i = 0; i < len; ++i)
6980
            {
6981
                if (JSON_UNLIKELY(not parse_cbor_internal()))
6982
                {
6983
                    return false;
6984
                }
6985
            }
6986
        else
6987
        {
6988
            while (get() != 0xFF)
6989
            {
6990
                if (JSON_UNLIKELY(not parse_cbor_internal(false)))
6991
                {
6992
                    return false;
6993
                }
6994
            }
6995
        }
6996
6997
        return sax->end_array();
6998
    }
6999
7000
    /*!
7001
    @param[in] len  the length of the object or std::size_t(-1) for an
7002
                    object of indefinite size
7003
    @return whether object creation completed
7004
    */
7005
    bool get_cbor_object(const std::size_t len)
7006
    {
7007
        if (not JSON_UNLIKELY(sax->start_object(len)))
7008
        {
7009
            return false;
7010
        }
7011
7012
        string_t key;
7013
        if (len != std::size_t(-1))
7014
        {
7015
            for (std::size_t i = 0; i < len; ++i)
7016
            {
7017
                get();
7018
                if (JSON_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))
7019
                {
7020
                    return false;
7021
                }
7022
7023
                if (JSON_UNLIKELY(not parse_cbor_internal()))
7024
                {
7025
                    return false;
7026
                }
7027
                key.clear();
7028
            }
7029
        }
7030
        else
7031
        {
7032
            while (get() != 0xFF)
7033
            {
7034
                if (JSON_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))
7035
                {
7036
                    return false;
7037
                }
7038
7039
                if (JSON_UNLIKELY(not parse_cbor_internal()))
7040
                {
7041
                    return false;
7042
                }
7043
                key.clear();
7044
            }
7045
        }
7046
7047
        return sax->end_object();
7048
    }
7049
7050
    /*!
7051
    @brief reads a MessagePack string
7052
7053
    This function first reads starting bytes to determine the expected
7054
    string length and then copies this number of bytes into a string.
7055
7056
    @param[out] result  created string
7057
7058
    @return whether string creation completed
7059
    */
7060
    bool get_msgpack_string(string_t& result)
7061
    {
7062
        if (JSON_UNLIKELY(not unexpect_eof()))
7063
        {
7064
            return false;
7065
        }
7066
7067
        switch (current)
7068
        {
7069
            // fixstr
7070
            case 0xA0:
7071
            case 0xA1:
7072
            case 0xA2:
7073
            case 0xA3:
7074
            case 0xA4:
7075
            case 0xA5:
7076
            case 0xA6:
7077
            case 0xA7:
7078
            case 0xA8:
7079
            case 0xA9:
7080
            case 0xAA:
7081
            case 0xAB:
7082
            case 0xAC:
7083
            case 0xAD:
7084
            case 0xAE:
7085
            case 0xAF:
7086
            case 0xB0:
7087
            case 0xB1:
7088
            case 0xB2:
7089
            case 0xB3:
7090
            case 0xB4:
7091
            case 0xB5:
7092
            case 0xB6:
7093
            case 0xB7:
7094
            case 0xB8:
7095
            case 0xB9:
7096
            case 0xBA:
7097
            case 0xBB:
7098
            case 0xBC:
7099
            case 0xBD:
7100
            case 0xBE:
7101
            case 0xBF:
7102
            {
7103
                return get_string(current & 0x1F, result);
7104
            }
7105
7106
            case 0xD9: // str 8
7107
            {
7108
                uint8_t len;
7109
                return get_number(len) and get_string(len, result);
7110
            }
7111
7112
            case 0xDA: // str 16
7113
            {
7114
                uint16_t len;
7115
                return get_number(len) and get_string(len, result);
7116
            }
7117
7118
            case 0xDB: // str 32
7119
            {
7120
                uint32_t len;
7121
                return get_number(len) and get_string(len, result);
7122
            }
7123
7124
            default:
7125
            {
7126
                auto last_token = get_token_string();
7127
                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "expected a MessagePack string; last byte: 0x" + last_token));
7128
            }
7129
        }
7130
    }
7131
7132
    /*!
7133
    @param[in] len  the length of the array
7134
    @return whether array creation completed
7135
    */
7136
    bool get_msgpack_array(const std::size_t len)
7137
    {
7138
        if (JSON_UNLIKELY(not sax->start_array(len)))
7139
        {
7140
            return false;
7141
        }
7142
7143
        for (std::size_t i = 0; i < len; ++i)
7144
        {
7145
            if (JSON_UNLIKELY(not parse_msgpack_internal()))
7146
            {
7147
                return false;
7148
            }
7149
        }
7150
7151
        return sax->end_array();
7152
    }
7153
7154
    /*!
7155
    @param[in] len  the length of the object
7156
    @return whether object creation completed
7157
    */
7158
    bool get_msgpack_object(const std::size_t len)
7159
    {
7160
        if (JSON_UNLIKELY(not sax->start_object(len)))
7161
        {
7162
            return false;
7163
        }
7164
7165
        string_t key;
7166
        for (std::size_t i = 0; i < len; ++i)
7167
        {
7168
            get();
7169
            if (JSON_UNLIKELY(not get_msgpack_string(key) or not sax->key(key)))
7170
            {
7171
                return false;
7172
            }
7173
7174
            if (JSON_UNLIKELY(not parse_msgpack_internal()))
7175
            {
7176
                return false;
7177
            }
7178
            key.clear();
7179
        }
7180
7181
        return sax->end_object();
7182
    }
7183
7184
    /*!
7185
    @brief reads a UBJSON string
7186
7187
    This function is either called after reading the 'S' byte explicitly
7188
    indicating a string, or in case of an object key where the 'S' byte can be
7189
    left out.
7190
7191
    @param[out] result   created string
7192
    @param[in] get_char  whether a new character should be retrieved from the
7193
                         input (true, default) or whether the last read
7194
                         character should be considered instead
7195
7196
    @return whether string creation completed
7197
    */
7198
    bool get_ubjson_string(string_t& result, const bool get_char = true)
7199
    {
7200
        if (get_char)
7201
        {
7202
            get();  // TODO: may we ignore N here?
7203
        }
7204
7205
        if (JSON_UNLIKELY(not unexpect_eof()))
7206
        {
7207
            return false;
7208
        }
7209
7210
        switch (current)
7211
        {
7212
            case 'U':
7213
            {
7214
                uint8_t len;
7215
                return get_number(len) and get_string(len, result);
7216
            }
7217
7218
            case 'i':
7219
            {
7220
                int8_t len;
7221
                return get_number(len) and get_string(len, result);
7222
            }
7223
7224
            case 'I':
7225
            {
7226
                int16_t len;
7227
                return get_number(len) and get_string(len, result);
7228
            }
7229
7230
            case 'l':
7231
            {
7232
                int32_t len;
7233
                return get_number(len) and get_string(len, result);
7234
            }
7235
7236
            case 'L':
7237
            {
7238
                int64_t len;
7239
                return get_number(len) and get_string(len, result);
7240
            }
7241
7242
            default:
7243
                auto last_token = get_token_string();
7244
                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "expected a UBJSON string; last byte: 0x" + last_token));
7245
        }
7246
    }
7247
7248
    /*!
7249
    @param[out] result  determined size
7250
    @return whether size determination completed
7251
    */
7252
    bool get_ubjson_size_value(std::size_t& result)
7253
    {
7254
        switch (get_ignore_noop())
7255
        {
7256
            case 'U':
7257
            {
7258
                uint8_t number;
7259
                if (JSON_UNLIKELY(not get_number(number)))
7260
                {
7261
                    return false;
7262
                }
7263
                result = static_cast<std::size_t>(number);
7264
                return true;
7265
            }
7266
7267
            case 'i':
7268
            {
7269
                int8_t number;
7270
                if (JSON_UNLIKELY(not get_number(number)))
7271
                {
7272
                    return false;
7273
                }
7274
                result = static_cast<std::size_t>(number);
7275
                return true;
7276
            }
7277
7278
            case 'I':
7279
            {
7280
                int16_t number;
7281
                if (JSON_UNLIKELY(not get_number(number)))
7282
                {
7283
                    return false;
7284
                }
7285
                result = static_cast<std::size_t>(number);
7286
                return true;
7287
            }
7288
7289
            case 'l':
7290
            {
7291
                int32_t number;
7292
                if (JSON_UNLIKELY(not get_number(number)))
7293
                {
7294
                    return false;
7295
                }
7296
                result = static_cast<std::size_t>(number);
7297
                return true;
7298
            }
7299
7300
            case 'L':
7301
            {
7302
                int64_t number;
7303
                if (JSON_UNLIKELY(not get_number(number)))
7304
                {
7305
                    return false;
7306
                }
7307
                result = static_cast<std::size_t>(number);
7308
                return true;
7309
            }
7310
7311
            default:
7312
            {
7313
                auto last_token = get_token_string();
7314
                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "byte after '#' must denote a number type; last byte: 0x" + last_token));
7315
            }
7316
        }
7317
    }
7318
7319
    /*!
7320
    @brief determine the type and size for a container
7321
7322
    In the optimized UBJSON format, a type and a size can be provided to allow
7323
    for a more compact representation.
7324
7325
    @param[out] result  pair of the size and the type
7326
7327
    @return whether pair creation completed
7328
    */
7329
    bool get_ubjson_size_type(std::pair<std::size_t, int>& result)
7330
    {
7331
        result.first = string_t::npos; // size
7332
        result.second = 0; // type
7333
7334
        get_ignore_noop();
7335
7336
        if (current == '$')
7337
        {
7338
            result.second = get();  // must not ignore 'N', because 'N' maybe the type
7339
            if (JSON_UNLIKELY(not unexpect_eof()))
7340
            {
7341
                return false;
7342
            }
7343
7344
            get_ignore_noop();
7345
            if (JSON_UNLIKELY(current != '#'))
7346
            {
7347
                if (JSON_UNLIKELY(not unexpect_eof()))
7348
                {
7349
                    return false;
7350
                }
7351
                auto last_token = get_token_string();
7352
                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "expected '#' after UBJSON type information; last byte: 0x" + last_token));
7353
            }
7354
7355
            return get_ubjson_size_value(result.first);
7356
        }
7357
        else if (current == '#')
7358
        {
7359
            return get_ubjson_size_value(result.first);
7360
        }
7361
        return true;
7362
    }
7363
7364
    /*!
7365
    @param prefix  the previously read or set type prefix
7366
    @return whether value creation completed
7367
    */
7368
    bool get_ubjson_value(const int prefix)
7369
    {
7370
        switch (prefix)
7371
        {
7372
            case std::char_traits<char>::eof():  // EOF
7373
                return unexpect_eof();
7374
7375
            case 'T':  // true
7376
                return sax->boolean(true);
7377
            case 'F':  // false
7378
                return sax->boolean(false);
7379
7380
            case 'Z':  // null
7381
                return sax->null();
7382
7383
            case 'U':
7384
            {
7385
                uint8_t number;
7386
                return get_number(number) and sax->number_unsigned(number);
7387
            }
7388
7389
            case 'i':
7390
            {
7391
                int8_t number;
7392
                return get_number(number) and sax->number_integer(number);
7393
            }
7394
7395
            case 'I':
7396
            {
7397
                int16_t number;
7398
                return get_number(number) and sax->number_integer(number);
7399
            }
7400
7401
            case 'l':
7402
            {
7403
                int32_t number;
7404
                return get_number(number) and sax->number_integer(number);
7405
            }
7406
7407
            case 'L':
7408
            {
7409
                int64_t number;
7410
                return get_number(number) and sax->number_integer(number);
7411
            }
7412
7413
            case 'd':
7414
            {
7415
                float number;
7416
                return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
7417
            }
7418
7419
            case 'D':
7420
            {
7421
                double number;
7422
                return get_number(number) and sax->number_float(static_cast<number_float_t>(number), "");
7423
            }
7424
7425
            case 'C':  // char
7426
            {
7427
                get();
7428
                if (JSON_UNLIKELY(not unexpect_eof()))
7429
                {
7430
                    return false;
7431
                }
7432
                if (JSON_UNLIKELY(current > 127))
7433
                {
7434
                    auto last_token = get_token_string();
7435
                    return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token));
7436
                }
7437
                string_t s(1, static_cast<char>(current));
7438
                return sax->string(s);
7439
            }
7440
7441
            case 'S':  // string
7442
            {
7443
                string_t s;
7444
                return get_ubjson_string(s) and sax->string(s);
7445
            }
7446
7447
            case '[':  // array
7448
                return get_ubjson_array();
7449
7450
            case '{':  // object
7451
                return get_ubjson_object();
7452
7453
            default: // anything else
7454
            {
7455
                auto last_token = get_token_string();
7456
                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, "error reading UBJSON; last byte: 0x" + last_token));
7457
            }
7458
        }
7459
    }
7460
7461
    /*!
7462
    @return whether array creation completed
7463
    */
7464
    bool get_ubjson_array()
7465
    {
7466
        std::pair<std::size_t, int> size_and_type;
7467
        if (JSON_UNLIKELY(not get_ubjson_size_type(size_and_type)))
7468
        {
7469
            return false;
7470
        }
7471
7472
        if (size_and_type.first != string_t::npos)
7473
        {
7474
            if (JSON_UNLIKELY(not sax->start_array(size_and_type.first)))
7475
            {
7476
                return false;
7477
            }
7478
7479
            if (size_and_type.second != 0)
7480
            {
7481
                if (size_and_type.second != 'N')
7482
                {
7483
                    for (std::size_t i = 0; i < size_and_type.first; ++i)
7484
                    {
7485
                        if (JSON_UNLIKELY(not get_ubjson_value(size_and_type.second)))
7486
                        {
7487
                            return false;
7488
                        }
7489
                    }
7490
                }
7491
            }
7492
            else
7493
            {
7494
                for (std::size_t i = 0; i < size_and_type.first; ++i)
7495
                {
7496
                    if (JSON_UNLIKELY(not parse_ubjson_internal()))
7497
                    {
7498
                        return false;
7499
                    }
7500
                }
7501
            }
7502
        }
7503
        else
7504
        {
7505
            if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))
7506
            {
7507
                return false;
7508
            }
7509
7510
            while (current != ']')
7511
            {
7512
                if (JSON_UNLIKELY(not parse_ubjson_internal(false)))
7513
                {
7514
                    return false;
7515
                }
7516
                get_ignore_noop();
7517
            }
7518
        }
7519
7520
        return sax->end_array();
7521
    }
7522
7523
    /*!
7524
    @return whether object creation completed
7525
    */
7526
    bool get_ubjson_object()
7527
    {
7528
        std::pair<std::size_t, int> size_and_type;
7529
        if (JSON_UNLIKELY(not get_ubjson_size_type(size_and_type)))
7530
        {
7531
            return false;
7532
        }
7533
7534
        string_t key;
7535
        if (size_and_type.first != string_t::npos)
7536
        {
7537
            if (JSON_UNLIKELY(not sax->start_object(size_and_type.first)))
7538
            {
7539
                return false;
7540
            }
7541
7542
            if (size_and_type.second != 0)
7543
            {
7544
                for (std::size_t i = 0; i < size_and_type.first; ++i)
7545
                {
7546
                    if (JSON_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))
7547
                    {
7548
                        return false;
7549
                    }
7550
                    if (JSON_UNLIKELY(not get_ubjson_value(size_and_type.second)))
7551
                    {
7552
                        return false;
7553
                    }
7554
                    key.clear();
7555
                }
7556
            }
7557
            else
7558
            {
7559
                for (std::size_t i = 0; i < size_and_type.first; ++i)
7560
                {
7561
                    if (JSON_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))
7562
                    {
7563
                        return false;
7564
                    }
7565
                    if (JSON_UNLIKELY(not parse_ubjson_internal()))
7566
                    {
7567
                        return false;
7568
                    }
7569
                    key.clear();
7570
                }
7571
            }
7572
        }
7573
        else
7574
        {
7575
            if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))
7576
            {
7577
                return false;
7578
            }
7579
7580
            while (current != '}')
7581
            {
7582
                if (JSON_UNLIKELY(not get_ubjson_string(key, false) or not sax->key(key)))
7583
                {
7584
                    return false;
7585
                }
7586
                if (JSON_UNLIKELY(not parse_ubjson_internal()))
7587
                {
7588
                    return false;
7589
                }
7590
                get_ignore_noop();
7591
                key.clear();
7592
            }
7593
        }
7594
7595
        return sax->end_object();
7596
    }
7597
7598
    /*!
7599
    @return whether the last read character is not EOF
7600
    */
7601
    bool unexpect_eof() const
7602
    {
7603
        if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))
7604
        {
7605
            return sax->parse_error(chars_read, "<end of file>", parse_error::create(110, chars_read, "unexpected end of input"));
7606
        }
7607
        return true;
7608
    }
7609
7610
    /*!
7611
    @return a string representation of the last read byte
7612
    */
7613
    std::string get_token_string() const
7614
    {
7615
        char cr[3];
7616
        snprintf(cr, 3, "%.2hhX", static_cast<unsigned char>(current));
7617
        return std::string{cr};
7618
    }
7619
7620
  private:
7621
    /// input adapter
7622
    input_adapter_t ia = nullptr;
7623
7624
    /// the current character
7625
    int current = std::char_traits<char>::eof();
7626
7627
    /// the number of characters read
7628
    std::size_t chars_read = 0;
7629
7630
    /// whether we can assume little endianess
7631
    const bool is_little_endian = little_endianess();
7632
7633
    /// the SAX parser
7634
    json_sax_t* sax = nullptr;
7635
};
7636
}
7637
}
7638
7639
// #include <nlohmann/detail/output/binary_writer.hpp>
7640
7641
7642
#include <algorithm> // reverse
7643
#include <array> // array
7644
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
7645
#include <cstring> // memcpy
7646
#include <limits> // numeric_limits
7647
7648
// #include <nlohmann/detail/input/binary_reader.hpp>
7649
7650
// #include <nlohmann/detail/output/output_adapters.hpp>
7651
7652
7653
namespace nlohmann
7654
{
7655
namespace detail
7656
{
7657
///////////////////
7658
// binary writer //
7659
///////////////////
7660
7661
/*!
7662
@brief serialization to CBOR and MessagePack values
7663
*/
7664
template<typename BasicJsonType, typename CharType>
7665
class binary_writer
7666
{
7667
  public:
7668
    /*!
7669
    @brief create a binary writer
7670
7671
    @param[in] adapter  output adapter to write to
7672
    */
7673
    explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter)
7674
    {
7675
        assert(oa);
7676
    }
7677
7678
    /*!
7679
    @brief[in] j  JSON value to serialize
7680
    */
7681
    void write_cbor(const BasicJsonType& j)
7682
    {
7683
        switch (j.type())
7684
        {
7685
            case value_t::null:
7686
            {
7687
                oa->write_character(static_cast<CharType>(0xF6));
7688
                break;
7689
            }
7690
7691
            case value_t::boolean:
7692
            {
7693
                oa->write_character(j.m_value.boolean
7694
                                    ? static_cast<CharType>(0xF5)
7695
                                    : static_cast<CharType>(0xF4));
7696
                break;
7697
            }
7698
7699
            case value_t::number_integer:
7700
            {
7701
                if (j.m_value.number_integer >= 0)
7702
                {
7703
                    // CBOR does not differentiate between positive signed
7704
                    // integers and unsigned integers. Therefore, we used the
7705
                    // code from the value_t::number_unsigned case here.
7706
                    if (j.m_value.number_integer <= 0x17)
7707
                    {
7708
                        write_number(static_cast<uint8_t>(j.m_value.number_integer));
7709
                    }
7710
                    else if (j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())
7711
                    {
7712
                        oa->write_character(static_cast<CharType>(0x18));
7713
                        write_number(static_cast<uint8_t>(j.m_value.number_integer));
7714
                    }
7715
                    else if (j.m_value.number_integer <= (std::numeric_limits<uint16_t>::max)())
7716
                    {
7717
                        oa->write_character(static_cast<CharType>(0x19));
7718
                        write_number(static_cast<uint16_t>(j.m_value.number_integer));
7719
                    }
7720
                    else if (j.m_value.number_integer <= (std::numeric_limits<uint32_t>::max)())
7721
                    {
7722
                        oa->write_character(static_cast<CharType>(0x1A));
7723
                        write_number(static_cast<uint32_t>(j.m_value.number_integer));
7724
                    }
7725
                    else
7726
                    {
7727
                        oa->write_character(static_cast<CharType>(0x1B));
7728
                        write_number(static_cast<uint64_t>(j.m_value.number_integer));
7729
                    }
7730
                }
7731
                else
7732
                {
7733
                    // The conversions below encode the sign in the first
7734
                    // byte, and the value is converted to a positive number.
7735
                    const auto positive_number = -1 - j.m_value.number_integer;
7736
                    if (j.m_value.number_integer >= -24)
7737
                    {
7738
                        write_number(static_cast<uint8_t>(0x20 + positive_number));
7739
                    }
7740
                    else if (positive_number <= (std::numeric_limits<uint8_t>::max)())
7741
                    {
7742
                        oa->write_character(static_cast<CharType>(0x38));
7743
                        write_number(static_cast<uint8_t>(positive_number));
7744
                    }
7745
                    else if (positive_number <= (std::numeric_limits<uint16_t>::max)())
7746
                    {
7747
                        oa->write_character(static_cast<CharType>(0x39));
7748
                        write_number(static_cast<uint16_t>(positive_number));
7749
                    }
7750
                    else if (positive_number <= (std::numeric_limits<uint32_t>::max)())
7751
                    {
7752
                        oa->write_character(static_cast<CharType>(0x3A));
7753
                        write_number(static_cast<uint32_t>(positive_number));
7754
                    }
7755
                    else
7756
                    {
7757
                        oa->write_character(static_cast<CharType>(0x3B));
7758
                        write_number(static_cast<uint64_t>(positive_number));
7759
                    }
7760
                }
7761
                break;
7762
            }
7763
7764
            case value_t::number_unsigned:
7765
            {
7766
                if (j.m_value.number_unsigned <= 0x17)
7767
                {
7768
                    write_number(static_cast<uint8_t>(j.m_value.number_unsigned));
7769
                }
7770
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
7771
                {
7772
                    oa->write_character(static_cast<CharType>(0x18));
7773
                    write_number(static_cast<uint8_t>(j.m_value.number_unsigned));
7774
                }
7775
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
7776
                {
7777
                    oa->write_character(static_cast<CharType>(0x19));
7778
                    write_number(static_cast<uint16_t>(j.m_value.number_unsigned));
7779
                }
7780
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
7781
                {
7782
                    oa->write_character(static_cast<CharType>(0x1A));
7783
                    write_number(static_cast<uint32_t>(j.m_value.number_unsigned));
7784
                }
7785
                else
7786
                {
7787
                    oa->write_character(static_cast<CharType>(0x1B));
7788
                    write_number(static_cast<uint64_t>(j.m_value.number_unsigned));
7789
                }
7790
                break;
7791
            }
7792
7793
            case value_t::number_float:
7794
            {
7795
                oa->write_character(get_cbor_float_prefix(j.m_value.number_float));
7796
                write_number(j.m_value.number_float);
7797
                break;
7798
            }
7799
7800
            case value_t::string:
7801
            {
7802
                // step 1: write control byte and the string length
7803
                const auto N = j.m_value.string->size();
7804
                if (N <= 0x17)
7805
                {
7806
                    write_number(static_cast<uint8_t>(0x60 + N));
7807
                }
7808
                else if (N <= (std::numeric_limits<uint8_t>::max)())
7809
                {
7810
                    oa->write_character(static_cast<CharType>(0x78));
7811
                    write_number(static_cast<uint8_t>(N));
7812
                }
7813
                else if (N <= (std::numeric_limits<uint16_t>::max)())
7814
                {
7815
                    oa->write_character(static_cast<CharType>(0x79));
7816
                    write_number(static_cast<uint16_t>(N));
7817
                }
7818
                else if (N <= (std::numeric_limits<uint32_t>::max)())
7819
                {
7820
                    oa->write_character(static_cast<CharType>(0x7A));
7821
                    write_number(static_cast<uint32_t>(N));
7822
                }
7823
                // LCOV_EXCL_START
7824
                else if (N <= (std::numeric_limits<uint64_t>::max)())
7825
                {
7826
                    oa->write_character(static_cast<CharType>(0x7B));
7827
                    write_number(static_cast<uint64_t>(N));
7828
                }
7829
                // LCOV_EXCL_STOP
7830
7831
                // step 2: write the string
7832
                oa->write_characters(
7833
                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
7834
                    j.m_value.string->size());
7835
                break;
7836
            }
7837
7838
            case value_t::array:
7839
            {
7840
                // step 1: write control byte and the array size
7841
                const auto N = j.m_value.array->size();
7842
                if (N <= 0x17)
7843
                {
7844
                    write_number(static_cast<uint8_t>(0x80 + N));
7845
                }
7846
                else if (N <= (std::numeric_limits<uint8_t>::max)())
7847
                {
7848
                    oa->write_character(static_cast<CharType>(0x98));
7849
                    write_number(static_cast<uint8_t>(N));
7850
                }
7851
                else if (N <= (std::numeric_limits<uint16_t>::max)())
7852
                {
7853
                    oa->write_character(static_cast<CharType>(0x99));
7854
                    write_number(static_cast<uint16_t>(N));
7855
                }
7856
                else if (N <= (std::numeric_limits<uint32_t>::max)())
7857
                {
7858
                    oa->write_character(static_cast<CharType>(0x9A));
7859
                    write_number(static_cast<uint32_t>(N));
7860
                }
7861
                // LCOV_EXCL_START
7862
                else if (N <= (std::numeric_limits<uint64_t>::max)())
7863
                {
7864
                    oa->write_character(static_cast<CharType>(0x9B));
7865
                    write_number(static_cast<uint64_t>(N));
7866
                }
7867
                // LCOV_EXCL_STOP
7868
7869
                // step 2: write each element
7870
                for (const auto& el : *j.m_value.array)
7871
                {
7872
                    write_cbor(el);
7873
                }
7874
                break;
7875
            }
7876
7877
            case value_t::object:
7878
            {
7879
                // step 1: write control byte and the object size
7880
                const auto N = j.m_value.object->size();
7881
                if (N <= 0x17)
7882
                {
7883
                    write_number(static_cast<uint8_t>(0xA0 + N));
7884
                }
7885
                else if (N <= (std::numeric_limits<uint8_t>::max)())
7886
                {
7887
                    oa->write_character(static_cast<CharType>(0xB8));
7888
                    write_number(static_cast<uint8_t>(N));
7889
                }
7890
                else if (N <= (std::numeric_limits<uint16_t>::max)())
7891
                {
7892
                    oa->write_character(static_cast<CharType>(0xB9));
7893
                    write_number(static_cast<uint16_t>(N));
7894
                }
7895
                else if (N <= (std::numeric_limits<uint32_t>::max)())
7896
                {
7897
                    oa->write_character(static_cast<CharType>(0xBA));
7898
                    write_number(static_cast<uint32_t>(N));
7899
                }
7900
                // LCOV_EXCL_START
7901
                else if (N <= (std::numeric_limits<uint64_t>::max)())
7902
                {
7903
                    oa->write_character(static_cast<CharType>(0xBB));
7904
                    write_number(static_cast<uint64_t>(N));
7905
                }
7906
                // LCOV_EXCL_STOP
7907
7908
                // step 2: write each element
7909
                for (const auto& el : *j.m_value.object)
7910
                {
7911
                    write_cbor(el.first);
7912
                    write_cbor(el.second);
7913
                }
7914
                break;
7915
            }
7916
7917
            default:
7918
                break;
7919
        }
7920
    }
7921
7922
    /*!
7923
    @brief[in] j  JSON value to serialize
7924
    */
7925
    void write_msgpack(const BasicJsonType& j)
7926
    {
7927
        switch (j.type())
7928
        {
7929
            case value_t::null: // nil
7930
            {
7931
                oa->write_character(static_cast<CharType>(0xC0));
7932
                break;
7933
            }
7934
7935
            case value_t::boolean: // true and false
7936
            {
7937
                oa->write_character(j.m_value.boolean
7938
                                    ? static_cast<CharType>(0xC3)
7939
                                    : static_cast<CharType>(0xC2));
7940
                break;
7941
            }
7942
7943
            case value_t::number_integer:
7944
            {
7945
                if (j.m_value.number_integer >= 0)
7946
                {
7947
                    // MessagePack does not differentiate between positive
7948
                    // signed integers and unsigned integers. Therefore, we used
7949
                    // the code from the value_t::number_unsigned case here.
7950
                    if (j.m_value.number_unsigned < 128)
7951
                    {
7952
                        // positive fixnum
7953
                        write_number(static_cast<uint8_t>(j.m_value.number_integer));
7954
                    }
7955
                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
7956
                    {
7957
                        // uint 8
7958
                        oa->write_character(static_cast<CharType>(0xCC));
7959
                        write_number(static_cast<uint8_t>(j.m_value.number_integer));
7960
                    }
7961
                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
7962
                    {
7963
                        // uint 16
7964
                        oa->write_character(static_cast<CharType>(0xCD));
7965
                        write_number(static_cast<uint16_t>(j.m_value.number_integer));
7966
                    }
7967
                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
7968
                    {
7969
                        // uint 32
7970
                        oa->write_character(static_cast<CharType>(0xCE));
7971
                        write_number(static_cast<uint32_t>(j.m_value.number_integer));
7972
                    }
7973
                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
7974
                    {
7975
                        // uint 64
7976
                        oa->write_character(static_cast<CharType>(0xCF));
7977
                        write_number(static_cast<uint64_t>(j.m_value.number_integer));
7978
                    }
7979
                }
7980
                else
7981
                {
7982
                    if (j.m_value.number_integer >= -32)
7983
                    {
7984
                        // negative fixnum
7985
                        write_number(static_cast<int8_t>(j.m_value.number_integer));
7986
                    }
7987
                    else if (j.m_value.number_integer >= (std::numeric_limits<int8_t>::min)() and
7988
                             j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())
7989
                    {
7990
                        // int 8
7991
                        oa->write_character(static_cast<CharType>(0xD0));
7992
                        write_number(static_cast<int8_t>(j.m_value.number_integer));
7993
                    }
7994
                    else if (j.m_value.number_integer >= (std::numeric_limits<int16_t>::min)() and
7995
                             j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())
7996
                    {
7997
                        // int 16
7998
                        oa->write_character(static_cast<CharType>(0xD1));
7999
                        write_number(static_cast<int16_t>(j.m_value.number_integer));
8000
                    }
8001
                    else if (j.m_value.number_integer >= (std::numeric_limits<int32_t>::min)() and
8002
                             j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())
8003
                    {
8004
                        // int 32
8005
                        oa->write_character(static_cast<CharType>(0xD2));
8006
                        write_number(static_cast<int32_t>(j.m_value.number_integer));
8007
                    }
8008
                    else if (j.m_value.number_integer >= (std::numeric_limits<int64_t>::min)() and
8009
                             j.m_value.number_integer <= (std::numeric_limits<int64_t>::max)())
8010
                    {
8011
                        // int 64
8012
                        oa->write_character(static_cast<CharType>(0xD3));
8013
                        write_number(static_cast<int64_t>(j.m_value.number_integer));
8014
                    }
8015
                }
8016
                break;
8017
            }
8018
8019
            case value_t::number_unsigned:
8020
            {
8021
                if (j.m_value.number_unsigned < 128)
8022
                {
8023
                    // positive fixnum
8024
                    write_number(static_cast<uint8_t>(j.m_value.number_integer));
8025
                }
8026
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
8027
                {
8028
                    // uint 8
8029
                    oa->write_character(static_cast<CharType>(0xCC));
8030
                    write_number(static_cast<uint8_t>(j.m_value.number_integer));
8031
                }
8032
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
8033
                {
8034
                    // uint 16
8035
                    oa->write_character(static_cast<CharType>(0xCD));
8036
                    write_number(static_cast<uint16_t>(j.m_value.number_integer));
8037
                }
8038
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
8039
                {
8040
                    // uint 32
8041
                    oa->write_character(static_cast<CharType>(0xCE));
8042
                    write_number(static_cast<uint32_t>(j.m_value.number_integer));
8043
                }
8044
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
8045
                {
8046
                    // uint 64
8047
                    oa->write_character(static_cast<CharType>(0xCF));
8048
                    write_number(static_cast<uint64_t>(j.m_value.number_integer));
8049
                }
8050
                break;
8051
            }
8052
8053
            case value_t::number_float:
8054
            {
8055
                oa->write_character(get_msgpack_float_prefix(j.m_value.number_float));
8056
                write_number(j.m_value.number_float);
8057
                break;
8058
            }
8059
8060
            case value_t::string:
8061
            {
8062
                // step 1: write control byte and the string length
8063
                const auto N = j.m_value.string->size();
8064
                if (N <= 31)
8065
                {
8066
                    // fixstr
8067
                    write_number(static_cast<uint8_t>(0xA0 | N));
8068
                }
8069
                else if (N <= (std::numeric_limits<uint8_t>::max)())
8070
                {
8071
                    // str 8
8072
                    oa->write_character(static_cast<CharType>(0xD9));
8073
                    write_number(static_cast<uint8_t>(N));
8074
                }
8075
                else if (N <= (std::numeric_limits<uint16_t>::max)())
8076
                {
8077
                    // str 16
8078
                    oa->write_character(static_cast<CharType>(0xDA));
8079
                    write_number(static_cast<uint16_t>(N));
8080
                }
8081
                else if (N <= (std::numeric_limits<uint32_t>::max)())
8082
                {
8083
                    // str 32
8084
                    oa->write_character(static_cast<CharType>(0xDB));
8085
                    write_number(static_cast<uint32_t>(N));
8086
                }
8087
8088
                // step 2: write the string
8089
                oa->write_characters(
8090
                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
8091
                    j.m_value.string->size());
8092
                break;
8093
            }
8094
8095
            case value_t::array:
8096
            {
8097
                // step 1: write control byte and the array size
8098
                const auto N = j.m_value.array->size();
8099
                if (N <= 15)
8100
                {
8101
                    // fixarray
8102
                    write_number(static_cast<uint8_t>(0x90 | N));
8103
                }
8104
                else if (N <= (std::numeric_limits<uint16_t>::max)())
8105
                {
8106
                    // array 16
8107
                    oa->write_character(static_cast<CharType>(0xDC));
8108
                    write_number(static_cast<uint16_t>(N));
8109
                }
8110
                else if (N <= (std::numeric_limits<uint32_t>::max)())
8111
                {
8112
                    // array 32
8113
                    oa->write_character(static_cast<CharType>(0xDD));
8114
                    write_number(static_cast<uint32_t>(N));
8115
                }
8116
8117
                // step 2: write each element
8118
                for (const auto& el : *j.m_value.array)
8119
                {
8120
                    write_msgpack(el);
8121
                }
8122
                break;
8123
            }
8124
8125
            case value_t::object:
8126
            {
8127
                // step 1: write control byte and the object size
8128
                const auto N = j.m_value.object->size();
8129
                if (N <= 15)
8130
                {
8131
                    // fixmap
8132
                    write_number(static_cast<uint8_t>(0x80 | (N & 0xF)));
8133
                }
8134
                else if (N <= (std::numeric_limits<uint16_t>::max)())
8135
                {
8136
                    // map 16
8137
                    oa->write_character(static_cast<CharType>(0xDE));
8138
                    write_number(static_cast<uint16_t>(N));
8139
                }
8140
                else if (N <= (std::numeric_limits<uint32_t>::max)())
8141
                {
8142
                    // map 32
8143
                    oa->write_character(static_cast<CharType>(0xDF));
8144
                    write_number(static_cast<uint32_t>(N));
8145
                }
8146
8147
                // step 2: write each element
8148
                for (const auto& el : *j.m_value.object)
8149
                {
8150
                    write_msgpack(el.first);
8151
                    write_msgpack(el.second);
8152
                }
8153
                break;
8154
            }
8155
8156
            default:
8157
                break;
8158
        }
8159
    }
8160
8161
    /*!
8162
    @param[in] j  JSON value to serialize
8163
    @param[in] use_count   whether to use '#' prefixes (optimized format)
8164
    @param[in] use_type    whether to use '$' prefixes (optimized format)
8165
    @param[in] add_prefix  whether prefixes need to be used for this value
8166
    */
8167
    void write_ubjson(const BasicJsonType& j, const bool use_count,
8168
                      const bool use_type, const bool add_prefix = true)
8169
    {
8170
        switch (j.type())
8171
        {
8172
            case value_t::null:
8173
            {
8174
                if (add_prefix)
8175
                {
8176
                    oa->write_character(static_cast<CharType>('Z'));
8177
                }
8178
                break;
8179
            }
8180
8181
            case value_t::boolean:
8182
            {
8183
                if (add_prefix)
8184
                    oa->write_character(j.m_value.boolean
8185
                                        ? static_cast<CharType>('T')
8186
                                        : static_cast<CharType>('F'));
8187
                break;
8188
            }
8189
8190
            case value_t::number_integer:
8191
            {
8192
                write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix);
8193
                break;
8194
            }
8195
8196
            case value_t::number_unsigned:
8197
            {
8198
                write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix);
8199
                break;
8200
            }
8201
8202
            case value_t::number_float:
8203
            {
8204
                write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix);
8205
                break;
8206
            }
8207
8208
            case value_t::string:
8209
            {
8210
                if (add_prefix)
8211
                {
8212
                    oa->write_character(static_cast<CharType>('S'));
8213
                }
8214
                write_number_with_ubjson_prefix(j.m_value.string->size(), true);
8215
                oa->write_characters(
8216
                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
8217
                    j.m_value.string->size());
8218
                break;
8219
            }
8220
8221
            case value_t::array:
8222
            {
8223
                if (add_prefix)
8224
                {
8225
                    oa->write_character(static_cast<CharType>('['));
8226
                }
8227
8228
                bool prefix_required = true;
8229
                if (use_type and not j.m_value.array->empty())
8230
                {
8231
                    assert(use_count);
8232
                    const CharType first_prefix = ubjson_prefix(j.front());
8233
                    const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
8234
                                                         [this, first_prefix](const BasicJsonType & v)
8235
                    {
8236
                        return ubjson_prefix(v) == first_prefix;
8237
                    });
8238
8239
                    if (same_prefix)
8240
                    {
8241
                        prefix_required = false;
8242
                        oa->write_character(static_cast<CharType>('$'));
8243
                        oa->write_character(first_prefix);
8244
                    }
8245
                }
8246
8247
                if (use_count)
8248
                {
8249
                    oa->write_character(static_cast<CharType>('#'));
8250
                    write_number_with_ubjson_prefix(j.m_value.array->size(), true);
8251
                }
8252
8253
                for (const auto& el : *j.m_value.array)
8254
                {
8255
                    write_ubjson(el, use_count, use_type, prefix_required);
8256
                }
8257
8258
                if (not use_count)
8259
                {
8260
                    oa->write_character(static_cast<CharType>(']'));
8261
                }
8262
8263
                break;
8264
            }
8265
8266
            case value_t::object:
8267
            {
8268
                if (add_prefix)
8269
                {
8270
                    oa->write_character(static_cast<CharType>('{'));
8271
                }
8272
8273
                bool prefix_required = true;
8274
                if (use_type and not j.m_value.object->empty())
8275
                {
8276
                    assert(use_count);
8277
                    const CharType first_prefix = ubjson_prefix(j.front());
8278
                    const bool same_prefix = std::all_of(j.begin(), j.end(),
8279
                                                         [this, first_prefix](const BasicJsonType & v)
8280
                    {
8281
                        return ubjson_prefix(v) == first_prefix;
8282
                    });
8283
8284
                    if (same_prefix)
8285
                    {
8286
                        prefix_required = false;
8287
                        oa->write_character(static_cast<CharType>('$'));
8288
                        oa->write_character(first_prefix);
8289
                    }
8290
                }
8291
8292
                if (use_count)
8293
                {
8294
                    oa->write_character(static_cast<CharType>('#'));
8295
                    write_number_with_ubjson_prefix(j.m_value.object->size(), true);
8296
                }
8297
8298
                for (const auto& el : *j.m_value.object)
8299
                {
8300
                    write_number_with_ubjson_prefix(el.first.size(), true);
8301
                    oa->write_characters(
8302
                        reinterpret_cast<const CharType*>(el.first.c_str()),
8303
                        el.first.size());
8304
                    write_ubjson(el.second, use_count, use_type, prefix_required);
8305
                }
8306
8307
                if (not use_count)
8308
                {
8309
                    oa->write_character(static_cast<CharType>('}'));
8310
                }
8311
8312
                break;
8313
            }
8314
8315
            default:
8316
                break;
8317
        }
8318
    }
8319
8320
  private:
8321
    /*
8322
    @brief write a number to output input
8323
8324
    @param[in] n number of type @a NumberType
8325
    @tparam NumberType the type of the number
8326
8327
    @note This function needs to respect the system's endianess, because bytes
8328
          in CBOR, MessagePack, and UBJSON are stored in network order (big
8329
          endian) and therefore need reordering on little endian systems.
8330
    */
8331
    template<typename NumberType>
8332
    void write_number(const NumberType n)
8333
    {
8334
        // step 1: write number to array of length NumberType
8335
        std::array<CharType, sizeof(NumberType)> vec;
8336
        std::memcpy(vec.data(), &n, sizeof(NumberType));
8337
8338
        // step 2: write array to output (with possible reordering)
8339
        if (is_little_endian)
8340
        {
8341
            // reverse byte order prior to conversion if necessary
8342
            std::reverse(vec.begin(), vec.end());
8343
        }
8344
8345
        oa->write_characters(vec.data(), sizeof(NumberType));
8346
    }
8347
8348
    // UBJSON: write number (floating point)
8349
    template<typename NumberType, typename std::enable_if<
8350
                 std::is_floating_point<NumberType>::value, int>::type = 0>
8351
    void write_number_with_ubjson_prefix(const NumberType n,
8352
                                         const bool add_prefix)
8353
    {
8354
        if (add_prefix)
8355
        {
8356
            oa->write_character(get_ubjson_float_prefix(n));
8357
        }
8358
        write_number(n);
8359
    }
8360
8361
    // UBJSON: write number (unsigned integer)
8362
    template<typename NumberType, typename std::enable_if<
8363
                 std::is_unsigned<NumberType>::value, int>::type = 0>
8364
    void write_number_with_ubjson_prefix(const NumberType n,
8365
                                         const bool add_prefix)
8366
    {
8367
        if (n <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)()))
8368
        {
8369
            if (add_prefix)
8370
            {
8371
                oa->write_character(static_cast<CharType>('i'));  // int8
8372
            }
8373
            write_number(static_cast<uint8_t>(n));
8374
        }
8375
        else if (n <= (std::numeric_limits<uint8_t>::max)())
8376
        {
8377
            if (add_prefix)
8378
            {
8379
                oa->write_character(static_cast<CharType>('U'));  // uint8
8380
            }
8381
            write_number(static_cast<uint8_t>(n));
8382
        }
8383
        else if (n <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)()))
8384
        {
8385
            if (add_prefix)
8386
            {
8387
                oa->write_character(static_cast<CharType>('I'));  // int16
8388
            }
8389
            write_number(static_cast<int16_t>(n));
8390
        }
8391
        else if (n <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
8392
        {
8393
            if (add_prefix)
8394
            {
8395
                oa->write_character(static_cast<CharType>('l'));  // int32
8396
            }
8397
            write_number(static_cast<int32_t>(n));
8398
        }
8399
        else if (n <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()))
8400
        {
8401
            if (add_prefix)
8402
            {
8403
                oa->write_character(static_cast<CharType>('L'));  // int64
8404
            }
8405
            write_number(static_cast<int64_t>(n));
8406
        }
8407
        else
8408
        {
8409
            JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
8410
        }
8411
    }
8412
8413
    // UBJSON: write number (signed integer)
8414
    template<typename NumberType, typename std::enable_if<
8415
                 std::is_signed<NumberType>::value and
8416
                 not std::is_floating_point<NumberType>::value, int>::type = 0>
8417
    void write_number_with_ubjson_prefix(const NumberType n,
8418
                                         const bool add_prefix)
8419
    {
8420
        if ((std::numeric_limits<int8_t>::min)() <= n and n <= (std::numeric_limits<int8_t>::max)())
8421
        {
8422
            if (add_prefix)
8423
            {
8424
                oa->write_character(static_cast<CharType>('i'));  // int8
8425
            }
8426
            write_number(static_cast<int8_t>(n));
8427
        }
8428
        else if (static_cast<int64_t>((std::numeric_limits<uint8_t>::min)()) <= n and n <= static_cast<int64_t>((std::numeric_limits<uint8_t>::max)()))
8429
        {
8430
            if (add_prefix)
8431
            {
8432
                oa->write_character(static_cast<CharType>('U'));  // uint8
8433
            }
8434
            write_number(static_cast<uint8_t>(n));
8435
        }
8436
        else if ((std::numeric_limits<int16_t>::min)() <= n and n <= (std::numeric_limits<int16_t>::max)())
8437
        {
8438
            if (add_prefix)
8439
            {
8440
                oa->write_character(static_cast<CharType>('I'));  // int16
8441
            }
8442
            write_number(static_cast<int16_t>(n));
8443
        }
8444
        else if ((std::numeric_limits<int32_t>::min)() <= n and n <= (std::numeric_limits<int32_t>::max)())
8445
        {
8446
            if (add_prefix)
8447
            {
8448
                oa->write_character(static_cast<CharType>('l'));  // int32
8449
            }
8450
            write_number(static_cast<int32_t>(n));
8451
        }
8452
        else if ((std::numeric_limits<int64_t>::min)() <= n and n <= (std::numeric_limits<int64_t>::max)())
8453
        {
8454
            if (add_prefix)
8455
            {
8456
                oa->write_character(static_cast<CharType>('L'));  // int64
8457
            }
8458
            write_number(static_cast<int64_t>(n));
8459
        }
8460
        // LCOV_EXCL_START
8461
        else
8462
        {
8463
            JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n)));
8464
        }
8465
        // LCOV_EXCL_STOP
8466
    }
8467
8468
    /*!
8469
    @brief determine the type prefix of container values
8470
8471
    @note This function does not need to be 100% accurate when it comes to
8472
          integer limits. In case a number exceeds the limits of int64_t,
8473
          this will be detected by a later call to function
8474
          write_number_with_ubjson_prefix. Therefore, we return 'L' for any
8475
          value that does not fit the previous limits.
8476
    */
8477
    CharType ubjson_prefix(const BasicJsonType& j) const noexcept
8478
    {
8479
        switch (j.type())
8480
        {
8481
            case value_t::null:
8482
                return 'Z';
8483
8484
            case value_t::boolean:
8485
                return j.m_value.boolean ? 'T' : 'F';
8486
8487
            case value_t::number_integer:
8488
            {
8489
                if ((std::numeric_limits<int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())
8490
                {
8491
                    return 'i';
8492
                }
8493
                else if ((std::numeric_limits<uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())
8494
                {
8495
                    return 'U';
8496
                }
8497
                else if ((std::numeric_limits<int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())
8498
                {
8499
                    return 'I';
8500
                }
8501
                else if ((std::numeric_limits<int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())
8502
                {
8503
                    return 'l';
8504
                }
8505
                else  // no check and assume int64_t (see note above)
8506
                {
8507
                    return 'L';
8508
                }
8509
            }
8510
8511
            case value_t::number_unsigned:
8512
            {
8513
                if (j.m_value.number_unsigned <= (std::numeric_limits<int8_t>::max)())
8514
                {
8515
                    return 'i';
8516
                }
8517
                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
8518
                {
8519
                    return 'U';
8520
                }
8521
                else if (j.m_value.number_unsigned <= (std::numeric_limits<int16_t>::max)())
8522
                {
8523
                    return 'I';
8524
                }
8525
                else if (j.m_value.number_unsigned <= (std::numeric_limits<int32_t>::max)())
8526
                {
8527
                    return 'l';
8528
                }
8529
                else  // no check and assume int64_t (see note above)
8530
                {
8531
                    return 'L';
8532
                }
8533
            }
8534
8535
            case value_t::number_float:
8536
                return get_ubjson_float_prefix(j.m_value.number_float);
8537
8538
            case value_t::string:
8539
                return 'S';
8540
8541
            case value_t::array:
8542
                return '[';
8543
8544
            case value_t::object:
8545
                return '{';
8546
8547
            default:  // discarded values
8548
                return 'N';
8549
        }
8550
    }
8551
8552
    static constexpr CharType get_cbor_float_prefix(float)
8553
    {
8554
        return static_cast<CharType>(0xFA);  // Single-Precision Float
8555
    }
8556
8557
    static constexpr CharType get_cbor_float_prefix(double)
8558
    {
8559
        return static_cast<CharType>(0xFB);  // Double-Precision Float
8560
    }
8561
8562
    static constexpr CharType get_msgpack_float_prefix(float)
8563
    {
8564
        return static_cast<CharType>(0xCA);  // float 32
8565
    }
8566
8567
    static constexpr CharType get_msgpack_float_prefix(double)
8568
    {
8569
        return static_cast<CharType>(0xCB);  // float 64
8570
    }
8571
8572
    static constexpr CharType get_ubjson_float_prefix(float)
8573
    {
8574
        return 'd';  // float 32
8575
    }
8576
8577
    static constexpr CharType get_ubjson_float_prefix(double)
8578
    {
8579
        return 'D';  // float 64
8580
    }
8581
8582
  private:
8583
    /// whether we can assume little endianess
8584
    const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();
8585
8586
    /// the output
8587
    output_adapter_t<CharType> oa = nullptr;
8588
};
8589
}
8590
}
8591
8592
// #include <nlohmann/detail/output/serializer.hpp>
8593
8594
8595
#include <algorithm> // reverse, remove, fill, find, none_of
8596
#include <array> // array
8597
#include <cassert> // assert
8598
#include <ciso646> // and, or
8599
#include <clocale> // localeconv, lconv
8600
#include <cmath> // labs, isfinite, isnan, signbit
8601
#include <cstddef> // size_t, ptrdiff_t
8602
#include <cstdint> // uint8_t
8603
#include <cstdio> // snprintf
8604
#include <limits> // numeric_limits
8605
#include <string> // string
8606
#include <type_traits> // is_same
8607
8608
// #include <nlohmann/detail/exceptions.hpp>
8609
8610
// #include <nlohmann/detail/conversions/to_chars.hpp>
8611
8612
8613
#include <cassert> // assert
8614
#include <ciso646> // or, and, not
8615
#include <cmath>   // signbit, isfinite
8616
#include <cstdint> // intN_t, uintN_t
8617
#include <cstring> // memcpy, memmove
8618
8619
namespace nlohmann
8620
{
8621
namespace detail
8622
{
8623
8624
/*!
8625
@brief implements the Grisu2 algorithm for binary to decimal floating-point
8626
conversion.
8627
8628
This implementation is a slightly modified version of the reference
8629
implementation which may be obtained from
8630
http://florian.loitsch.com/publications (bench.tar.gz).
8631
8632
The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.
8633
8634
For a detailed description of the algorithm see:
8635
8636
[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with
8637
    Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming
8638
    Language Design and Implementation, PLDI 2010
8639
[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately",
8640
    Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language
8641
    Design and Implementation, PLDI 1996
8642
*/
8643
namespace dtoa_impl
8644
{
8645
8646
template <typename Target, typename Source>
8647
Target reinterpret_bits(const Source source)
8648
28
{
8649
28
    static_assert(sizeof(Target) == sizeof(Source), "size mismatch");
8650
28
8651
28
    Target target;
8652
28
    std::memcpy(&target, &source, sizeof(Source));
8653
28
    return target;
8654
28
}
8655
8656
struct diyfp // f * 2^e
8657
{
8658
    static constexpr int kPrecision = 64; // = q
8659
8660
    uint64_t f;
8661
    int e;
8662
8663
0
    constexpr diyfp() noexcept : f(0), e(0) {}
8664
364
    constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {}
8665
8666
    /*!
8667
    @brief returns x - y
8668
    @pre x.e == y.e and x.f >= y.f
8669
    */
8670
    static diyfp sub(const diyfp& x, const diyfp& y) noexcept
8671
56
    {
8672
56
        assert(x.e == y.e);
8673
56
        assert(x.f >= y.f);
8674
56
8675
56
        return diyfp(x.f - y.f, x.e);
8676
56
    }
8677
8678
    /*!
8679
    @brief returns x * y
8680
    @note The result is rounded. (Only the upper q bits are returned.)
8681
    */
8682
    static diyfp mul(const diyfp& x, const diyfp& y) noexcept
8683
84
    {
8684
84
        static_assert(kPrecision == 64, "internal error");
8685
84
8686
84
        // Computes:
8687
84
        //  f = round((x.f * y.f) / 2^q)
8688
84
        //  e = x.e + y.e + q
8689
84
8690
84
        // Emulate the 64-bit * 64-bit multiplication:
8691
84
        //
8692
84
        // p = u * v
8693
84
        //   = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi)
8694
84
        //   = (u_lo v_lo         ) + 2^32 ((u_lo v_hi         ) + (u_hi v_lo         )) + 2^64 (u_hi v_hi         )
8695
84
        //   = (p0                ) + 2^32 ((p1                ) + (p2                )) + 2^64 (p3                )
8696
84
        //   = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3                )
8697
84
        //   = (p0_lo             ) + 2^32 (p0_hi + p1_lo + p2_lo                      ) + 2^64 (p1_hi + p2_hi + p3)
8698
84
        //   = (p0_lo             ) + 2^32 (Q                                          ) + 2^64 (H                 )
8699
84
        //   = (p0_lo             ) + 2^32 (Q_lo + 2^32 Q_hi                           ) + 2^64 (H                 )
8700
84
        //
8701
84
        // (Since Q might be larger than 2^32 - 1)
8702
84
        //
8703
84
        //   = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H)
8704
84
        //
8705
84
        // (Q_hi + H does not overflow a 64-bit int)
8706
84
        //
8707
84
        //   = p_lo + 2^64 p_hi
8708
84
8709
84
        const uint64_t u_lo = x.f & 0xFFFFFFFF;
8710
84
        const uint64_t u_hi = x.f >> 32;
8711
84
        const uint64_t v_lo = y.f & 0xFFFFFFFF;
8712
84
        const uint64_t v_hi = y.f >> 32;
8713
84
8714
84
        const uint64_t p0 = u_lo * v_lo;
8715
84
        const uint64_t p1 = u_lo * v_hi;
8716
84
        const uint64_t p2 = u_hi * v_lo;
8717
84
        const uint64_t p3 = u_hi * v_hi;
8718
84
8719
84
        const uint64_t p0_hi = p0 >> 32;
8720
84
        const uint64_t p1_lo = p1 & 0xFFFFFFFF;
8721
84
        const uint64_t p1_hi = p1 >> 32;
8722
84
        const uint64_t p2_lo = p2 & 0xFFFFFFFF;
8723
84
        const uint64_t p2_hi = p2 >> 32;
8724
84
8725
84
        uint64_t Q = p0_hi + p1_lo + p2_lo;
8726
84
8727
84
        // The full product might now be computed as
8728
84
        //
8729
84
        // p_hi = p3 + p2_hi + p1_hi + (Q >> 32)
8730
84
        // p_lo = p0_lo + (Q << 32)
8731
84
        //
8732
84
        // But in this particular case here, the full p_lo is not required.
8733
84
        // Effectively we only need to add the highest bit in p_lo to p_hi (and
8734
84
        // Q_hi + 1 does not overflow).
8735
84
8736
84
        Q += uint64_t{1} << (64 - 32 - 1); // round, ties up
8737
84
8738
84
        const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32);
8739
84
8740
84
        return diyfp(h, x.e + y.e + 64);
8741
84
    }
8742
8743
    /*!
8744
    @brief normalize x such that the significand is >= 2^(q-1)
8745
    @pre x.f != 0
8746
    */
8747
    static diyfp normalize(diyfp x) noexcept
8748
56
    {
8749
56
        assert(x.f != 0);
8750
56
8751
644
        while ((x.f >> 63) == 0)
8752
588
        {
8753
588
            x.f <<= 1;
8754
588
            x.e--;
8755
588
        }
8756
56
8757
56
        return x;
8758
56
    }
8759
8760
    /*!
8761
    @brief normalize x such that the result has the exponent E
8762
    @pre e >= x.e and the upper e - x.e bits of x.f must be zero.
8763
    */
8764
    static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept
8765
28
    {
8766
28
        const int delta = x.e - target_exponent;
8767
28
8768
28
        assert(delta >= 0);
8769
28
        assert(((x.f << delta) >> delta) == x.f);
8770
28
8771
28
        return diyfp(x.f << delta, target_exponent);
8772
28
    }
8773
};
8774
8775
struct boundaries
8776
{
8777
    diyfp w;
8778
    diyfp minus;
8779
    diyfp plus;
8780
};
8781
8782
/*!
8783
Compute the (normalized) diyfp representing the input number 'value' and its
8784
boundaries.
8785
8786
@pre value must be finite and positive
8787
*/
8788
template <typename FloatType>
8789
boundaries compute_boundaries(FloatType value)
8790
28
{
8791
28
    assert(std::isfinite(value));
8792
28
    assert(value > 0);
8793
28
8794
28
    // Convert the IEEE representation into a diyfp.
8795
28
    //
8796
28
    // If v is denormal:
8797
28
    //      value = 0.F * 2^(1 - bias) = (          F) * 2^(1 - bias - (p-1))
8798
28
    // If v is normalized:
8799
28
    //      value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1))
8800
28
8801
28
    static_assert(std::numeric_limits<FloatType>::is_iec559,
8802
28
                  "internal error: dtoa_short requires an IEEE-754 floating-point implementation");
8803
28
8804
28
    constexpr int      kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)
8805
28
    constexpr int      kBias      = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);
8806
28
    constexpr int      kMinExp    = 1 - kBias;
8807
28
    constexpr uint64_t kHiddenBit = uint64_t{1} << (kPrecision - 1); // = 2^(p-1)
8808
28
8809
28
    using bits_type = typename std::conditional< kPrecision == 24, uint32_t, uint64_t >::type;
8810
28
8811
28
    const uint64_t bits = reinterpret_bits<bits_type>(value);
8812
28
    const uint64_t E = bits >> (kPrecision - 1);
8813
28
    const uint64_t F = bits & (kHiddenBit - 1);
8814
28
8815
28
    const bool is_denormal = (E == 0);
8816
28
    const diyfp v = is_denormal
8817
28
                    ? diyfp(F, kMinExp)
8818
28
                    : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);
8819
28
8820
28
    // Compute the boundaries m- and m+ of the floating-point value
8821
28
    // v = f * 2^e.
8822
28
    //
8823
28
    // Determine v- and v+, the floating-point predecessor and successor if v,
8824
28
    // respectively.
8825
28
    //
8826
28
    //      v- = v - 2^e        if f != 2^(p-1) or e == e_min                (A)
8827
28
    //         = v - 2^(e-1)    if f == 2^(p-1) and e > e_min                (B)
8828
28
    //
8829
28
    //      v+ = v + 2^e
8830
28
    //
8831
28
    // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_
8832
28
    // between m- and m+ round to v, regardless of how the input rounding
8833
28
    // algorithm breaks ties.
8834
28
    //
8835
28
    //      ---+-------------+-------------+-------------+-------------+---  (A)
8836
28
    //         v-            m-            v             m+            v+
8837
28
    //
8838
28
    //      -----------------+------+------+-------------+-------------+---  (B)
8839
28
    //                       v-     m-     v             m+            v+
8840
28
8841
28
    const bool lower_boundary_is_closer = (F == 0 and E > 1);
8842
28
    const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);
8843
28
    const diyfp m_minus = lower_boundary_is_closer
8844
28
                          ? diyfp(4 * v.f - 1, v.e - 2)  // (B)
8845
28
                          : diyfp(2 * v.f - 1, v.e - 1); // (A)
8846
28
8847
28
    // Determine the normalized w+ = m+.
8848
28
    const diyfp w_plus = diyfp::normalize(m_plus);
8849
28
8850
28
    // Determine w- = m- such that e_(w-) = e_(w+).
8851
28
    const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e);
8852
28
8853
28
    return {diyfp::normalize(v), w_minus, w_plus};
8854
28
}
8855
8856
// Given normalized diyfp w, Grisu needs to find a (normalized) cached
8857
// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies
8858
// within a certain range [alpha, gamma] (Definition 3.2 from [1])
8859
//
8860
//      alpha <= e = e_c + e_w + q <= gamma
8861
//
8862
// or
8863
//
8864
//      f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q
8865
//                          <= f_c * f_w * 2^gamma
8866
//
8867
// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies
8868
//
8869
//      2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma
8870
//
8871
// or
8872
//
8873
//      2^(q - 2 + alpha) <= c * w < 2^(q + gamma)
8874
//
8875
// The choice of (alpha,gamma) determines the size of the table and the form of
8876
// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well
8877
// in practice:
8878
//
8879
// The idea is to cut the number c * w = f * 2^e into two parts, which can be
8880
// processed independently: An integral part p1, and a fractional part p2:
8881
//
8882
//      f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e
8883
//              = (f div 2^-e) + (f mod 2^-e) * 2^e
8884
//              = p1 + p2 * 2^e
8885
//
8886
// The conversion of p1 into decimal form requires a series of divisions and
8887
// modulos by (a power of) 10. These operations are faster for 32-bit than for
8888
// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be
8889
// achieved by choosing
8890
//
8891
//      -e >= 32   or   e <= -32 := gamma
8892
//
8893
// In order to convert the fractional part
8894
//
8895
//      p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ...
8896
//
8897
// into decimal form, the fraction is repeatedly multiplied by 10 and the digits
8898
// d[-i] are extracted in order:
8899
//
8900
//      (10 * p2) div 2^-e = d[-1]
8901
//      (10 * p2) mod 2^-e = d[-2] / 10^1 + ...
8902
//
8903
// The multiplication by 10 must not overflow. It is sufficient to choose
8904
//
8905
//      10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64.
8906
//
8907
// Since p2 = f mod 2^-e < 2^-e,
8908
//
8909
//      -e <= 60   or   e >= -60 := alpha
8910
8911
constexpr int kAlpha = -60;
8912
constexpr int kGamma = -32;
8913
8914
struct cached_power // c = f * 2^e ~= 10^k
8915
{
8916
    uint64_t f;
8917
    int e;
8918
    int k;
8919
};
8920
8921
/*!
8922
For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached
8923
power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c
8924
satisfies (Definition 3.2 from [1])
8925
8926
     alpha <= e_c + e + q <= gamma.
8927
*/
8928
inline cached_power get_cached_power_for_binary_exponent(int e)
8929
28
{
8930
28
    // Now
8931
28
    //
8932
28
    //      alpha <= e_c + e + q <= gamma                                    (1)
8933
28
    //      ==> f_c * 2^alpha <= c * 2^e * 2^q
8934
28
    //
8935
28
    // and since the c's are normalized, 2^(q-1) <= f_c,
8936
28
    //
8937
28
    //      ==> 2^(q - 1 + alpha) <= c * 2^(e + q)
8938
28
    //      ==> 2^(alpha - e - 1) <= c
8939
28
    //
8940
28
    // If c were an exakt power of ten, i.e. c = 10^k, one may determine k as
8941
28
    //
8942
28
    //      k = ceil( log_10( 2^(alpha - e - 1) ) )
8943
28
    //        = ceil( (alpha - e - 1) * log_10(2) )
8944
28
    //
8945
28
    // From the paper:
8946
28
    // "In theory the result of the procedure could be wrong since c is rounded,
8947
28
    //  and the computation itself is approximated [...]. In practice, however,
8948
28
    //  this simple function is sufficient."
8949
28
    //
8950
28
    // For IEEE double precision floating-point numbers converted into
8951
28
    // normalized diyfp's w = f * 2^e, with q = 64,
8952
28
    //
8953
28
    //      e >= -1022      (min IEEE exponent)
8954
28
    //           -52        (p - 1)
8955
28
    //           -52        (p - 1, possibly normalize denormal IEEE numbers)
8956
28
    //           -11        (normalize the diyfp)
8957
28
    //         = -1137
8958
28
    //
8959
28
    // and
8960
28
    //
8961
28
    //      e <= +1023      (max IEEE exponent)
8962
28
    //           -52        (p - 1)
8963
28
    //           -11        (normalize the diyfp)
8964
28
    //         = 960
8965
28
    //
8966
28
    // This binary exponent range [-1137,960] results in a decimal exponent
8967
28
    // range [-307,324]. One does not need to store a cached power for each
8968
28
    // k in this range. For each such k it suffices to find a cached power
8969
28
    // such that the exponent of the product lies in [alpha,gamma].
8970
28
    // This implies that the difference of the decimal exponents of adjacent
8971
28
    // table entries must be less than or equal to
8972
28
    //
8973
28
    //      floor( (gamma - alpha) * log_10(2) ) = 8.
8974
28
    //
8975
28
    // (A smaller distance gamma-alpha would require a larger table.)
8976
28
8977
28
    // NB:
8978
28
    // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.
8979
28
8980
28
    constexpr int kCachedPowersSize = 79;
8981
28
    constexpr int kCachedPowersMinDecExp = -300;
8982
28
    constexpr int kCachedPowersDecStep = 8;
8983
28
8984
28
    static constexpr cached_power kCachedPowers[] =
8985
28
    {
8986
28
        { 0xAB70FE17C79AC6CA, -1060, -300 },
8987
28
        { 0xFF77B1FCBEBCDC4F, -1034, -292 },
8988
28
        { 0xBE5691EF416BD60C, -1007, -284 },
8989
28
        { 0x8DD01FAD907FFC3C,  -980, -276 },
8990
28
        { 0xD3515C2831559A83,  -954, -268 },
8991
28
        { 0x9D71AC8FADA6C9B5,  -927, -260 },
8992
28
        { 0xEA9C227723EE8BCB,  -901, -252 },
8993
28
        { 0xAECC49914078536D,  -874, -244 },
8994
28
        { 0x823C12795DB6CE57,  -847, -236 },
8995
28
        { 0xC21094364DFB5637,  -821, -228 },
8996
28
        { 0x9096EA6F3848984F,  -794, -220 },
8997
28
        { 0xD77485CB25823AC7,  -768, -212 },
8998
28
        { 0xA086CFCD97BF97F4,  -741, -204 },
8999
28
        { 0xEF340A98172AACE5,  -715, -196 },
9000
28
        { 0xB23867FB2A35B28E,  -688, -188 },
9001
28
        { 0x84C8D4DFD2C63F3B,  -661, -180 },
9002
28
        { 0xC5DD44271AD3CDBA,  -635, -172 },
9003
28
        { 0x936B9FCEBB25C996,  -608, -164 },
9004
28
        { 0xDBAC6C247D62A584,  -582, -156 },
9005
28
        { 0xA3AB66580D5FDAF6,  -555, -148 },
9006
28
        { 0xF3E2F893DEC3F126,  -529, -140 },
9007
28
        { 0xB5B5ADA8AAFF80B8,  -502, -132 },
9008
28
        { 0x87625F056C7C4A8B,  -475, -124 },
9009
28
        { 0xC9BCFF6034C13053,  -449, -116 },
9010
28
        { 0x964E858C91BA2655,  -422, -108 },
9011
28
        { 0xDFF9772470297EBD,  -396, -100 },
9012
28
        { 0xA6DFBD9FB8E5B88F,  -369,  -92 },
9013
28
        { 0xF8A95FCF88747D94,  -343,  -84 },
9014
28
        { 0xB94470938FA89BCF,  -316,  -76 },
9015
28
        { 0x8A08F0F8BF0F156B,  -289,  -68 },
9016
28
        { 0xCDB02555653131B6,  -263,  -60 },
9017
28
        { 0x993FE2C6D07B7FAC,  -236,  -52 },
9018
28
        { 0xE45C10C42A2B3B06,  -210,  -44 },
9019
28
        { 0xAA242499697392D3,  -183,  -36 },
9020
28
        { 0xFD87B5F28300CA0E,  -157,  -28 },
9021
28
        { 0xBCE5086492111AEB,  -130,  -20 },
9022
28
        { 0x8CBCCC096F5088CC,  -103,  -12 },
9023
28
        { 0xD1B71758E219652C,   -77,   -4 },
9024
28
        { 0x9C40000000000000,   -50,    4 },
9025
28
        { 0xE8D4A51000000000,   -24,   12 },
9026
28
        { 0xAD78EBC5AC620000,     3,   20 },
9027
28
        { 0x813F3978F8940984,    30,   28 },
9028
28
        { 0xC097CE7BC90715B3,    56,   36 },
9029
28
        { 0x8F7E32CE7BEA5C70,    83,   44 },
9030
28
        { 0xD5D238A4ABE98068,   109,   52 },
9031
28
        { 0x9F4F2726179A2245,   136,   60 },
9032
28
        { 0xED63A231D4C4FB27,   162,   68 },
9033
28
        { 0xB0DE65388CC8ADA8,   189,   76 },
9034
28
        { 0x83C7088E1AAB65DB,   216,   84 },
9035
28
        { 0xC45D1DF942711D9A,   242,   92 },
9036
28
        { 0x924D692CA61BE758,   269,  100 },
9037
28
        { 0xDA01EE641A708DEA,   295,  108 },
9038
28
        { 0xA26DA3999AEF774A,   322,  116 },
9039
28
        { 0xF209787BB47D6B85,   348,  124 },
9040
28
        { 0xB454E4A179DD1877,   375,  132 },
9041
28
        { 0x865B86925B9BC5C2,   402,  140 },
9042
28
        { 0xC83553C5C8965D3D,   428,  148 },
9043
28
        { 0x952AB45CFA97A0B3,   455,  156 },
9044
28
        { 0xDE469FBD99A05FE3,   481,  164 },
9045
28
        { 0xA59BC234DB398C25,   508,  172 },
9046
28
        { 0xF6C69A72A3989F5C,   534,  180 },
9047
28
        { 0xB7DCBF5354E9BECE,   561,  188 },
9048
28
        { 0x88FCF317F22241E2,   588,  196 },
9049
28
        { 0xCC20CE9BD35C78A5,   614,  204 },
9050
28
        { 0x98165AF37B2153DF,   641,  212 },
9051
28
        { 0xE2A0B5DC971F303A,   667,  220 },
9052
28
        { 0xA8D9D1535CE3B396,   694,  228 },
9053
28
        { 0xFB9B7CD9A4A7443C,   720,  236 },
9054
28
        { 0xBB764C4CA7A44410,   747,  244 },
9055
28
        { 0x8BAB8EEFB6409C1A,   774,  252 },
9056
28
        { 0xD01FEF10A657842C,   800,  260 },
9057
28
        { 0x9B10A4E5E9913129,   827,  268 },
9058
28
        { 0xE7109BFBA19C0C9D,   853,  276 },
9059
28
        { 0xAC2820D9623BF429,   880,  284 },
9060
28
        { 0x80444B5E7AA7CF85,   907,  292 },
9061
28
        { 0xBF21E44003ACDD2D,   933,  300 },
9062
28
        { 0x8E679C2F5E44FF8F,   960,  308 },
9063
28
        { 0xD433179D9C8CB841,   986,  316 },
9064
28
        { 0x9E19DB92B4E31BA9,  1013,  324 },
9065
28
    };
9066
28
9067
28
    // This computation gives exactly the same results for k as
9068
28
    //      k = ceil((kAlpha - e - 1) * 0.30102999566398114)
9069
28
    // for |e| <= 1500, but doesn't require floating-point operations.
9070
28
    // NB: log_10(2) ~= 78913 / 2^18
9071
28
    assert(e >= -1500);
9072
28
    assert(e <=  1500);
9073
28
    const int f = kAlpha - e - 1;
9074
28
    const int k = (f * 78913) / (1 << 18) + (f > 0);
9075
28
9076
28
    const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;
9077
28
    assert(index >= 0);
9078
28
    assert(index < kCachedPowersSize);
9079
28
    static_cast<void>(kCachedPowersSize); // Fix warning.
9080
28
9081
28
    const cached_power cached = kCachedPowers[index];
9082
28
    assert(kAlpha <= cached.e + e + 64);
9083
28
    assert(kGamma >= cached.e + e + 64);
9084
28
9085
28
    return cached;
9086
28
}
9087
9088
/*!
9089
For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.
9090
For n == 0, returns 1 and sets pow10 := 1.
9091
*/
9092
inline int find_largest_pow10(const uint32_t n, uint32_t& pow10)
9093
28
{
9094
28
    // LCOV_EXCL_START
9095
28
    if (n >= 1000000000)
9096
0
    {
9097
0
        pow10 = 1000000000;
9098
0
        return 10;
9099
0
    }
9100
28
    // LCOV_EXCL_STOP
9101
28
    else if (n >= 100000000)
9102
0
    {
9103
0
        pow10 = 100000000;
9104
0
        return  9;
9105
0
    }
9106
28
    else if (n >= 10000000)
9107
0
    {
9108
0
        pow10 = 10000000;
9109
0
        return  8;
9110
0
    }
9111
28
    else if (n >= 1000000)
9112
0
    {
9113
0
        pow10 = 1000000;
9114
0
        return  7;
9115
0
    }
9116
28
    else if (n >= 100000)
9117
24
    {
9118
24
        pow10 = 100000;
9119
24
        return  6;
9120
24
    }
9121
4
    else if (n >= 10000)
9122
4
    {
9123
4
        pow10 = 10000;
9124
4
        return  5;
9125
4
    }
9126
0
    else if (n >= 1000)
9127
0
    {
9128
0
        pow10 = 1000;
9129
0
        return  4;
9130
0
    }
9131
0
    else if (n >= 100)
9132
0
    {
9133
0
        pow10 = 100;
9134
0
        return  3;
9135
0
    }
9136
0
    else if (n >= 10)
9137
0
    {
9138
0
        pow10 = 10;
9139
0
        return  2;
9140
0
    }
9141
0
    else
9142
0
    {
9143
0
        pow10 = 1;
9144
0
        return 1;
9145
0
    }
9146
0
}
9147
9148
inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta,
9149
                         uint64_t rest, uint64_t ten_k)
9150
28
{
9151
28
    assert(len >= 1);
9152
28
    assert(dist <= delta);
9153
28
    assert(rest <= delta);
9154
28
    assert(ten_k > 0);
9155
28
9156
28
    //               <--------------------------- delta ---->
9157
28
    //                                  <---- dist --------->
9158
28
    // --------------[------------------+-------------------]--------------
9159
28
    //               M-                 w                   M+
9160
28
    //
9161
28
    //                                  ten_k
9162
28
    //                                <------>
9163
28
    //                                       <---- rest ---->
9164
28
    // --------------[------------------+----+--------------]--------------
9165
28
    //                                  w    V
9166
28
    //                                       = buf * 10^k
9167
28
    //
9168
28
    // ten_k represents a unit-in-the-last-place in the decimal representation
9169
28
    // stored in buf.
9170
28
    // Decrement buf by ten_k while this takes buf closer to w.
9171
28
9172
28
    // The tests are written in this order to avoid overflow in unsigned
9173
28
    // integer arithmetic.
9174
28
9175
28
    while (rest < dist
9176
28
            and delta - rest >= ten_k
9177
28
            and (rest + ten_k < dist or dist - rest > rest + ten_k - dist))
9178
0
    {
9179
0
        assert(buf[len - 1] != '0');
9180
0
        buf[len - 1]--;
9181
0
        rest += ten_k;
9182
0
    }
9183
28
}
9184
9185
/*!
9186
Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.
9187
M- and M+ must be normalized and share the same exponent -60 <= e <= -32.
9188
*/
9189
inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
9190
                             diyfp M_minus, diyfp w, diyfp M_plus)
9191
28
{
9192
28
    static_assert(kAlpha >= -60, "internal error");
9193
28
    static_assert(kGamma <= -32, "internal error");
9194
28
9195
28
    // Generates the digits (and the exponent) of a decimal floating-point
9196
28
    // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's
9197
28
    // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma.
9198
28
    //
9199
28
    //               <--------------------------- delta ---->
9200
28
    //                                  <---- dist --------->
9201
28
    // --------------[------------------+-------------------]--------------
9202
28
    //               M-                 w                   M+
9203
28
    //
9204
28
    // Grisu2 generates the digits of M+ from left to right and stops as soon as
9205
28
    // V is in [M-,M+].
9206
28
9207
28
    assert(M_plus.e >= kAlpha);
9208
28
    assert(M_plus.e <= kGamma);
9209
28
9210
28
    uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)
9211
28
    uint64_t dist  = diyfp::sub(M_plus, w      ).f; // (significand of (M+ - w ), implicit exponent is e)
9212
28
9213
28
    // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):
9214
28
    //
9215
28
    //      M+ = f * 2^e
9216
28
    //         = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e
9217
28
    //         = ((p1        ) * 2^-e + (p2        )) * 2^e
9218
28
    //         = p1 + p2 * 2^e
9219
28
9220
28
    const diyfp one(uint64_t{1} << -M_plus.e, M_plus.e);
9221
28
9222
28
    uint32_t p1 = static_cast<uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)
9223
28
    uint64_t p2 = M_plus.f & (one.f - 1);                    // p2 = f mod 2^-e
9224
28
9225
28
    // 1)
9226
28
    //
9227
28
    // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]
9228
28
9229
28
    assert(p1 > 0);
9230
28
9231
28
    uint32_t pow10;
9232
28
    const int k = find_largest_pow10(p1, pow10);
9233
28
9234
28
    //      10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)
9235
28
    //
9236
28
    //      p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1))
9237
28
    //         = (d[k-1]         ) * 10^(k-1) + (p1 mod 10^(k-1))
9238
28
    //
9239
28
    //      M+ = p1                                             + p2 * 2^e
9240
28
    //         = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1))          + p2 * 2^e
9241
28
    //         = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e
9242
28
    //         = d[k-1] * 10^(k-1) + (                         rest) * 2^e
9243
28
    //
9244
28
    // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0)
9245
28
    //
9246
28
    //      p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0]
9247
28
    //
9248
28
    // but stop as soon as
9249
28
    //
9250
28
    //      rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e
9251
28
9252
28
    int n = k;
9253
164
    while (n > 0)
9254
148
    {
9255
148
        // Invariants:
9256
148
        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)    (buffer = 0 for n = k)
9257
148
        //      pow10 = 10^(n-1) <= p1 < 10^n
9258
148
        //
9259
148
        const uint32_t d = p1 / pow10;  // d = p1 div 10^(n-1)
9260
148
        const uint32_t r = p1 % pow10;  // r = p1 mod 10^(n-1)
9261
148
        //
9262
148
        //      M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e
9263
148
        //         = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)
9264
148
        //
9265
148
        assert(d <= 9);
9266
148
        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
9267
148
        //
9268
148
        //      M+ = buffer * 10^(n-1) + (r + p2 * 2^e)
9269
148
        //
9270
148
        p1 = r;
9271
148
        n--;
9272
148
        //
9273
148
        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)
9274
148
        //      pow10 = 10^n
9275
148
        //
9276
148
9277
148
        // Now check if enough digits have been generated.
9278
148
        // Compute
9279
148
        //
9280
148
        //      p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e
9281
148
        //
9282
148
        // Note:
9283
148
        // Since rest and delta share the same exponent e, it suffices to
9284
148
        // compare the significands.
9285
148
        const uint64_t rest = (uint64_t{p1} << -one.e) + p2;
9286
148
        if (rest <= delta)
9287
12
        {
9288
12
            // V = buffer * 10^n, with M- <= V <= M+.
9289
12
9290
12
            decimal_exponent += n;
9291
12
9292
12
            // We may now just stop. But instead look if the buffer could be
9293
12
            // decremented to bring V closer to w.
9294
12
            //
9295
12
            // pow10 = 10^n is now 1 ulp in the decimal representation V.
9296
12
            // The rounding procedure works with diyfp's with an implicit
9297
12
            // exponent of e.
9298
12
            //
9299
12
            //      10^n = (10^n * 2^-e) * 2^e = ulp * 2^e
9300
12
            //
9301
12
            const uint64_t ten_n = uint64_t{pow10} << -one.e;
9302
12
            grisu2_round(buffer, length, dist, delta, rest, ten_n);
9303
12
9304
12
            return;
9305
12
        }
9306
136
9307
136
        pow10 /= 10;
9308
136
        //
9309
136
        //      pow10 = 10^(n-1) <= p1 < 10^n
9310
136
        // Invariants restored.
9311
136
    }
9312
28
9313
28
    // 2)
9314
28
    //
9315
28
    // The digits of the integral part have been generated:
9316
28
    //
9317
28
    //      M+ = d[k-1]...d[1]d[0] + p2 * 2^e
9318
28
    //         = buffer            + p2 * 2^e
9319
28
    //
9320
28
    // Now generate the digits of the fractional part p2 * 2^e.
9321
28
    //
9322
28
    // Note:
9323
28
    // No decimal point is generated: the exponent is adjusted instead.
9324
28
    //
9325
28
    // p2 actually represents the fraction
9326
28
    //
9327
28
    //      p2 * 2^e
9328
28
    //          = p2 / 2^-e
9329
28
    //          = d[-1] / 10^1 + d[-2] / 10^2 + ...
9330
28
    //
9331
28
    // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...)
9332
28
    //
9333
28
    //      p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m
9334
28
    //                      + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...)
9335
28
    //
9336
28
    // using
9337
28
    //
9338
28
    //      10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e)
9339
28
    //                = (                   d) * 2^-e + (                   r)
9340
28
    //
9341
28
    // or
9342
28
    //      10^m * p2 * 2^e = d + r * 2^e
9343
28
    //
9344
28
    // i.e.
9345
28
    //
9346
28
    //      M+ = buffer + p2 * 2^e
9347
28
    //         = buffer + 10^-m * (d + r * 2^e)
9348
28
    //         = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e
9349
28
    //
9350
28
    // and stop as soon as 10^-m * r * 2^e <= delta * 2^e
9351
28
9352
28
    assert(p2 > delta);
9353
16
9354
16
    int m = 0;
9355
16
    for (;;)
9356
16
    {
9357
16
        // Invariant:
9358
16
        //      M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e
9359
16
        //         = buffer * 10^-m + 10^-m * (p2                                 ) * 2^e
9360
16
        //         = buffer * 10^-m + 10^-m * (1/10 * (10 * p2)                   ) * 2^e
9361
16
        //         = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e
9362
16
        //
9363
16
        assert(p2 <= UINT64_MAX / 10);
9364
16
        p2 *= 10;
9365
16
        const uint64_t d = p2 >> -one.e;     // d = (10 * p2) div 2^-e
9366
16
        const uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e
9367
16
        //
9368
16
        //      M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e
9369
16
        //         = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))
9370
16
        //         = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e
9371
16
        //
9372
16
        assert(d <= 9);
9373
16
        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
9374
16
        //
9375
16
        //      M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e
9376
16
        //
9377
16
        p2 = r;
9378
16
        m++;
9379
16
        //
9380
16
        //      M+ = buffer * 10^-m + 10^-m * p2 * 2^e
9381
16
        // Invariant restored.
9382
16
9383
16
        // Check if enough digits have been generated.
9384
16
        //
9385
16
        //      10^-m * p2 * 2^e <= delta * 2^e
9386
16
        //              p2 * 2^e <= 10^m * delta * 2^e
9387
16
        //                    p2 <= 10^m * delta
9388
16
        delta *= 10;
9389
16
        dist  *= 10;
9390
16
        if (p2 <= delta)
9391
16
        {
9392
16
            break;
9393
16
        }
9394
16
    }
9395
16
9396
16
    // V = buffer * 10^-m, with M- <= V <= M+.
9397
16
9398
16
    decimal_exponent -= m;
9399
16
9400
16
    // 1 ulp in the decimal representation is now 10^-m.
9401
16
    // Since delta and dist are now scaled by 10^m, we need to do the
9402
16
    // same with ulp in order to keep the units in sync.
9403
16
    //
9404
16
    //      10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e
9405
16
    //
9406
16
    const uint64_t ten_m = one.f;
9407
16
    grisu2_round(buffer, length, dist, delta, p2, ten_m);
9408
16
9409
16
    // By construction this algorithm generates the shortest possible decimal
9410
16
    // number (Loitsch, Theorem 6.2) which rounds back to w.
9411
16
    // For an input number of precision p, at least
9412
16
    //
9413
16
    //      N = 1 + ceil(p * log_10(2))
9414
16
    //
9415
16
    // decimal digits are sufficient to identify all binary floating-point
9416
16
    // numbers (Matula, "In-and-Out conversions").
9417
16
    // This implies that the algorithm does not produce more than N decimal
9418
16
    // digits.
9419
16
    //
9420
16
    //      N = 17 for p = 53 (IEEE double precision)
9421
16
    //      N = 9  for p = 24 (IEEE single precision)
9422
16
}
9423
9424
/*!
9425
v = buf * 10^decimal_exponent
9426
len is the length of the buffer (number of decimal digits)
9427
The buffer must be large enough, i.e. >= max_digits10.
9428
*/
9429
inline void grisu2(char* buf, int& len, int& decimal_exponent,
9430
                   diyfp m_minus, diyfp v, diyfp m_plus)
9431
28
{
9432
28
    assert(m_plus.e == m_minus.e);
9433
28
    assert(m_plus.e == v.e);
9434
28
9435
28
    //  --------(-----------------------+-----------------------)--------    (A)
9436
28
    //          m-                      v                       m+
9437
28
    //
9438
28
    //  --------------------(-----------+-----------------------)--------    (B)
9439
28
    //                      m-          v                       m+
9440
28
    //
9441
28
    // First scale v (and m- and m+) such that the exponent is in the range
9442
28
    // [alpha, gamma].
9443
28
9444
28
    const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e);
9445
28
9446
28
    const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k
9447
28
9448
28
    // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]
9449
28
    const diyfp w       = diyfp::mul(v,       c_minus_k);
9450
28
    const diyfp w_minus = diyfp::mul(m_minus, c_minus_k);
9451
28
    const diyfp w_plus  = diyfp::mul(m_plus,  c_minus_k);
9452
28
9453
28
    //  ----(---+---)---------------(---+---)---------------(---+---)----
9454
28
    //          w-                      w                       w+
9455
28
    //          = c*m-                  = c*v                   = c*m+
9456
28
    //
9457
28
    // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and
9458
28
    // w+ are now off by a small amount.
9459
28
    // In fact:
9460
28
    //
9461
28
    //      w - v * 10^k < 1 ulp
9462
28
    //
9463
28
    // To account for this inaccuracy, add resp. subtract 1 ulp.
9464
28
    //
9465
28
    //  --------+---[---------------(---+---)---------------]---+--------
9466
28
    //          w-  M-                  w                   M+  w+
9467
28
    //
9468
28
    // Now any number in [M-, M+] (bounds included) will round to w when input,
9469
28
    // regardless of how the input rounding algorithm breaks ties.
9470
28
    //
9471
28
    // And digit_gen generates the shortest possible such number in [M-, M+].
9472
28
    // Note that this does not mean that Grisu2 always generates the shortest
9473
28
    // possible number in the interval (m-, m+).
9474
28
    const diyfp M_minus(w_minus.f + 1, w_minus.e);
9475
28
    const diyfp M_plus (w_plus.f  - 1, w_plus.e );
9476
28
9477
28
    decimal_exponent = -cached.k; // = -(-k) = k
9478
28
9479
28
    grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);
9480
28
}
9481
9482
/*!
9483
v = buf * 10^decimal_exponent
9484
len is the length of the buffer (number of decimal digits)
9485
The buffer must be large enough, i.e. >= max_digits10.
9486
*/
9487
template <typename FloatType>
9488
void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
9489
28
{
9490
28
    static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,
9491
28
                  "internal error: not enough precision");
9492
28
9493
28
    assert(std::isfinite(value));
9494
28
    assert(value > 0);
9495
28
9496
28
    // If the neighbors (and boundaries) of 'value' are always computed for double-precision
9497
28
    // numbers, all float's can be recovered using strtod (and strtof). However, the resulting
9498
28
    // decimal representations are not exactly "short".
9499
28
    //
9500
28
    // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars)
9501
28
    // says "value is converted to a string as if by std::sprintf in the default ("C") locale"
9502
28
    // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars'
9503
28
    // does.
9504
28
    // On the other hand, the documentation for 'std::to_chars' requires that "parsing the
9505
28
    // representation using the corresponding std::from_chars function recovers value exactly". That
9506
28
    // indicates that single precision floating-point numbers should be recovered using
9507
28
    // 'std::strtof'.
9508
28
    //
9509
28
    // NB: If the neighbors are computed for single-precision numbers, there is a single float
9510
28
    //     (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision
9511
28
    //     value is off by 1 ulp.
9512
#if 0
9513
    const boundaries w = compute_boundaries(static_cast<double>(value));
9514
#else
9515
    const boundaries w = compute_boundaries(value);
9516
28
#endif
9517
28
9518
28
    grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);
9519
28
}
9520
9521
/*!
9522
@brief appends a decimal representation of e to buf
9523
@return a pointer to the element following the exponent.
9524
@pre -1000 < e < 1000
9525
*/
9526
inline char* append_exponent(char* buf, int e)
9527
0
{
9528
0
    assert(e > -1000);
9529
0
    assert(e <  1000);
9530
0
9531
0
    if (e < 0)
9532
0
    {
9533
0
        e = -e;
9534
0
        *buf++ = '-';
9535
0
    }
9536
0
    else
9537
0
    {
9538
0
        *buf++ = '+';
9539
0
    }
9540
0
9541
0
    uint32_t k = static_cast<uint32_t>(e);
9542
0
    if (k < 10)
9543
0
    {
9544
0
        // Always print at least two digits in the exponent.
9545
0
        // This is for compatibility with printf("%g").
9546
0
        *buf++ = '0';
9547
0
        *buf++ = static_cast<char>('0' + k);
9548
0
    }
9549
0
    else if (k < 100)
9550
0
    {
9551
0
        *buf++ = static_cast<char>('0' + k / 10);
9552
0
        k %= 10;
9553
0
        *buf++ = static_cast<char>('0' + k);
9554
0
    }
9555
0
    else
9556
0
    {
9557
0
        *buf++ = static_cast<char>('0' + k / 100);
9558
0
        k %= 100;
9559
0
        *buf++ = static_cast<char>('0' + k / 10);
9560
0
        k %= 10;
9561
0
        *buf++ = static_cast<char>('0' + k);
9562
0
    }
9563
0
9564
0
    return buf;
9565
0
}
9566
9567
/*!
9568
@brief prettify v = buf * 10^decimal_exponent
9569
9570
If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point
9571
notation. Otherwise it will be printed in exponential notation.
9572
9573
@pre min_exp < 0
9574
@pre max_exp > 0
9575
*/
9576
inline char* format_buffer(char* buf, int len, int decimal_exponent,
9577
                           int min_exp, int max_exp)
9578
28
{
9579
28
    assert(min_exp < 0);
9580
28
    assert(max_exp > 0);
9581
28
9582
28
    const int k = len;
9583
28
    const int n = len + decimal_exponent;
9584
28
9585
28
    // v = buf * 10^(n-k)
9586
28
    // k is the length of the buffer (number of decimal digits)
9587
28
    // n is the position of the decimal point relative to the start of the buffer.
9588
28
9589
28
    if (k <= n and n <= max_exp)
9590
0
    {
9591
0
        // digits[000]
9592
0
        // len <= max_exp + 2
9593
0
9594
0
        std::memset(buf + k, '0', static_cast<size_t>(n - k));
9595
0
        // Make it look like a floating-point number (#362, #378)
9596
0
        buf[n + 0] = '.';
9597
0
        buf[n + 1] = '0';
9598
0
        return buf + (n + 2);
9599
0
    }
9600
28
9601
28
    if (0 < n and n <= max_exp)
9602
28
    {
9603
28
        // dig.its
9604
28
        // len <= max_digits10 + 1
9605
28
9606
28
        assert(k > n);
9607
28
9608
28
        std::memmove(buf + (n + 1), buf + n, static_cast<size_t>(k - n));
9609
28
        buf[n] = '.';
9610
28
        return buf + (k + 1);
9611
28
    }
9612
0
9613
0
    if (min_exp < n and n <= 0)
9614
0
    {
9615
0
        // 0.[000]digits
9616
0
        // len <= 2 + (-min_exp - 1) + max_digits10
9617
0
9618
0
        std::memmove(buf + (2 + -n), buf, static_cast<size_t>(k));
9619
0
        buf[0] = '0';
9620
0
        buf[1] = '.';
9621
0
        std::memset(buf + 2, '0', static_cast<size_t>(-n));
9622
0
        return buf + (2 + (-n) + k);
9623
0
    }
9624
0
9625
0
    if (k == 1)
9626
0
    {
9627
0
        // dE+123
9628
0
        // len <= 1 + 5
9629
0
9630
0
        buf += 1;
9631
0
    }
9632
0
    else
9633
0
    {
9634
0
        // d.igitsE+123
9635
0
        // len <= max_digits10 + 1 + 5
9636
0
9637
0
        std::memmove(buf + 2, buf + 1, static_cast<size_t>(k - 1));
9638
0
        buf[1] = '.';
9639
0
        buf += 1 + k;
9640
0
    }
9641
0
9642
0
    *buf++ = 'e';
9643
0
    return append_exponent(buf, n - 1);
9644
0
}
9645
9646
} // namespace dtoa_impl
9647
9648
/*!
9649
@brief generates a decimal representation of the floating-point number value in [first, last).
9650
9651
The format of the resulting decimal representation is similar to printf's %g
9652
format. Returns an iterator pointing past-the-end of the decimal representation.
9653
9654
@note The input number must be finite, i.e. NaN's and Inf's are not supported.
9655
@note The buffer must be large enough.
9656
@note The result is NOT null-terminated.
9657
*/
9658
template <typename FloatType>
9659
char* to_chars(char* first, char* last, FloatType value)
9660
28
{
9661
28
    static_cast<void>(last); // maybe unused - fix warning
9662
28
    assert(std::isfinite(value));
9663
28
9664
28
    // Use signbit(value) instead of (value < 0) since signbit works for -0.
9665
28
    if (std::signbit(value))
9666
0
    {
9667
0
        value = -value;
9668
0
        *first++ = '-';
9669
0
    }
9670
28
9671
28
    if (value == 0) // +-0
9672
0
    {
9673
0
        *first++ = '0';
9674
0
        // Make it look like a floating-point number (#362, #378)
9675
0
        *first++ = '.';
9676
0
        *first++ = '0';
9677
0
        return first;
9678
0
    }
9679
28
9680
28
    assert(last - first >= std::numeric_limits<FloatType>::max_digits10);
9681
28
9682
28
    // Compute v = buffer * 10^decimal_exponent.
9683
28
    // The decimal digits are stored in the buffer, which needs to be interpreted
9684
28
    // as an unsigned decimal integer.
9685
28
    // len is the length of the buffer, i.e. the number of decimal digits.
9686
28
    int len = 0;
9687
28
    int decimal_exponent = 0;
9688
28
    dtoa_impl::grisu2(first, len, decimal_exponent, value);
9689
28
9690
28
    assert(len <= std::numeric_limits<FloatType>::max_digits10);
9691
28
9692
28
    // Format the buffer like printf("%.*g", prec, value)
9693
28
    constexpr int kMinExp = -4;
9694
28
    // Use digits10 here to increase compatibility with version 2.
9695
28
    constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;
9696
28
9697
28
    assert(last - first >= kMaxExp + 2);
9698
28
    assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
9699
28
    assert(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
9700
28
9701
28
    return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);
9702
28
}
9703
9704
} // namespace detail
9705
} // namespace nlohmann
9706
9707
// #include <nlohmann/detail/macro_scope.hpp>
9708
9709
// #include <nlohmann/detail/meta/cpp_future.hpp>
9710
9711
// #include <nlohmann/detail/output/output_adapters.hpp>
9712
9713
// #include <nlohmann/detail/value_t.hpp>
9714
9715
9716
namespace nlohmann
9717
{
9718
namespace detail
9719
{
9720
///////////////////
9721
// serialization //
9722
///////////////////
9723
9724
template<typename BasicJsonType>
9725
class serializer
9726
{
9727
    using string_t = typename BasicJsonType::string_t;
9728
    using number_float_t = typename BasicJsonType::number_float_t;
9729
    using number_integer_t = typename BasicJsonType::number_integer_t;
9730
    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
9731
    static constexpr uint8_t UTF8_ACCEPT = 0;
9732
    static constexpr uint8_t UTF8_REJECT = 1;
9733
9734
  public:
9735
    /*!
9736
    @param[in] s  output stream to serialize to
9737
    @param[in] ichar  indentation character to use
9738
    */
9739
    serializer(output_adapter_t<char> s, const char ichar)
9740
        : o(std::move(s)), loc(std::localeconv()),
9741
          thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)),
9742
          decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)),
9743
          indent_char(ichar), indent_string(512, indent_char)
9744
508
    {}
9745
9746
    // delete because of pointer members
9747
    serializer(const serializer&) = delete;
9748
    serializer& operator=(const serializer&) = delete;
9749
9750
    /*!
9751
    @brief internal implementation of the serialization function
9752
9753
    This function is called by the public member function dump and organizes
9754
    the serialization internally. The indentation level is propagated as
9755
    additional parameter. In case of arrays and objects, the function is
9756
    called recursively.
9757
9758
    - strings and object keys are escaped using `escape_string()`
9759
    - integer numbers are converted implicitly via `operator<<`
9760
    - floating-point numbers are converted to a string using `"%g"` format
9761
9762
    @param[in] val             value to serialize
9763
    @param[in] pretty_print    whether the output shall be pretty-printed
9764
    @param[in] indent_step     the indent level
9765
    @param[in] current_indent  the current indent level (only used internally)
9766
    */
9767
    void dump(const BasicJsonType& val, const bool pretty_print,
9768
              const bool ensure_ascii,
9769
              const unsigned int indent_step,
9770
              const unsigned int current_indent = 0)
9771
10.9k
    {
9772
10.9k
        switch (val.m_type)
9773
10.9k
        {
9774
10.9k
            case value_t::object:
9775
2.51k
            {
9776
2.51k
                if (val.m_value.object->empty())
9777
0
                {
9778
0
                    o->write_characters("{}", 2);
9779
0
                    return;
9780
0
                }
9781
2.51k
9782
2.51k
                if (pretty_print)
9783
1.52k
                {
9784
1.52k
                    o->write_characters("{\n", 2);
9785
1.52k
9786
1.52k
                    // variable to hold indentation for recursive calls
9787
1.52k
                    const auto new_indent = current_indent + indent_step;
9788
1.52k
                    if (JSON_UNLIKELY(indent_string.size() < new_indent))
9789
1.52k
                    {
9790
0
                        indent_string.resize(indent_string.size() * 2, ' ');
9791
0
                    }
9792
1.52k
9793
1.52k
                    // first n-1 elements
9794
1.52k
                    auto i = val.m_value.object->cbegin();
9795
7.13k
                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
9796
5.61k
                    {
9797
5.61k
                        o->write_characters(indent_string.c_str(), new_indent);
9798
5.61k
                        o->write_character('\"');
9799
5.61k
                        dump_escaped(i->first, ensure_ascii);
9800
5.61k
                        o->write_characters("\": ", 3);
9801
5.61k
                        dump(i->second, true, ensure_ascii, indent_step, new_indent);
9802
5.61k
                        o->write_characters(",\n", 2);
9803
5.61k
                    }
9804
1.52k
9805
1.52k
                    // last element
9806
1.52k
                    assert(i != val.m_value.object->cend());
9807
1.52k
                    assert(std::next(i) == val.m_value.object->cend());
9808
1.52k
                    o->write_characters(indent_string.c_str(), new_indent);
9809
1.52k
                    o->write_character('\"');
9810
1.52k
                    dump_escaped(i->first, ensure_ascii);
9811
1.52k
                    o->write_characters("\": ", 3);
9812
1.52k
                    dump(i->second, true, ensure_ascii, indent_step, new_indent);
9813
1.52k
9814
1.52k
                    o->write_character('\n');
9815
1.52k
                    o->write_characters(indent_string.c_str(), current_indent);
9816
1.52k
                    o->write_character('}');
9817
1.52k
                }
9818
988
                else
9819
988
                {
9820
988
                    o->write_character('{');
9821
988
9822
988
                    // first n-1 elements
9823
988
                    auto i = val.m_value.object->cbegin();
9824
3.34k
                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
9825
2.35k
                    {
9826
2.35k
                        o->write_character('\"');
9827
2.35k
                        dump_escaped(i->first, ensure_ascii);
9828
2.35k
                        o->write_characters("\":", 2);
9829
2.35k
                        dump(i->second, false, ensure_ascii, indent_step, current_indent);
9830
2.35k
                        o->write_character(',');
9831
2.35k
                    }
9832
988
9833
988
                    // last element
9834
988
                    assert(i != val.m_value.object->cend());
9835
988
                    assert(std::next(i) == val.m_value.object->cend());
9836
988
                    o->write_character('\"');
9837
988
                    dump_escaped(i->first, ensure_ascii);
9838
988
                    o->write_characters("\":", 2);
9839
988
                    dump(i->second, false, ensure_ascii, indent_step, current_indent);
9840
988
9841
988
                    o->write_character('}');
9842
988
                }
9843
2.51k
9844
2.51k
                return;
9845
2.51k
            }
9846
2.51k
9847
2.51k
            case value_t::array:
9848
4
            {
9849
4
                if (val.m_value.array->empty())
9850
0
                {
9851
0
                    o->write_characters("[]", 2);
9852
0
                    return;
9853
0
                }
9854
4
9855
4
                if (pretty_print)
9856
4
                {
9857
4
                    o->write_characters("[\n", 2);
9858
4
9859
4
                    // variable to hold indentation for recursive calls
9860
4
                    const auto new_indent = current_indent + indent_step;
9861
4
                    if (JSON_UNLIKELY(indent_string.size() < new_indent))
9862
4
                    {
9863
0
                        indent_string.resize(indent_string.size() * 2, ' ');
9864
0
                    }
9865
4
9866
4
                    // first n-1 elements
9867
4
                    for (auto i = val.m_value.array->cbegin();
9868
4
                            i != val.m_value.array->cend() - 1; ++i)
9869
0
                    {
9870
0
                        o->write_characters(indent_string.c_str(), new_indent);
9871
0
                        dump(*i, true, ensure_ascii, indent_step, new_indent);
9872
0
                        o->write_characters(",\n", 2);
9873
0
                    }
9874
4
9875
4
                    // last element
9876
4
                    assert(not val.m_value.array->empty());
9877
4
                    o->write_characters(indent_string.c_str(), new_indent);
9878
4
                    dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
9879
4
9880
4
                    o->write_character('\n');
9881
4
                    o->write_characters(indent_string.c_str(), current_indent);
9882
4
                    o->write_character(']');
9883
4
                }
9884
0
                else
9885
0
                {
9886
0
                    o->write_character('[');
9887
0
9888
0
                    // first n-1 elements
9889
0
                    for (auto i = val.m_value.array->cbegin();
9890
0
                            i != val.m_value.array->cend() - 1; ++i)
9891
0
                    {
9892
0
                        dump(*i, false, ensure_ascii, indent_step, current_indent);
9893
0
                        o->write_character(',');
9894
0
                    }
9895
0
9896
0
                    // last element
9897
0
                    assert(not val.m_value.array->empty());
9898
0
                    dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
9899
0
9900
0
                    o->write_character(']');
9901
0
                }
9902
4
9903
4
                return;
9904
4
            }
9905
4
9906
7.15k
            case value_t::string:
9907
7.15k
            {
9908
7.15k
                o->write_character('\"');
9909
7.15k
                dump_escaped(*val.m_value.string, ensure_ascii);
9910
7.15k
                o->write_character('\"');
9911
7.15k
                return;
9912
4
            }
9913
4
9914
8
            case value_t::boolean:
9915
8
            {
9916
8
                if (val.m_value.boolean)
9917
8
                {
9918
8
                    o->write_characters("true", 4);
9919
8
                }
9920
0
                else
9921
0
                {
9922
0
                    o->write_characters("false", 5);
9923
0
                }
9924
8
                return;
9925
4
            }
9926
4
9927
8
            case value_t::number_integer:
9928
8
            {
9929
8
                dump_integer(val.m_value.number_integer);
9930
8
                return;
9931
4
            }
9932
4
9933
1.22k
            case value_t::number_unsigned:
9934
1.22k
            {
9935
1.22k
                dump_integer(val.m_value.number_unsigned);
9936
1.22k
                return;
9937
4
            }
9938
4
9939
28
            case value_t::number_float:
9940
28
            {
9941
28
                dump_float(val.m_value.number_float);
9942
28
                return;
9943
4
            }
9944
4
9945
4
            case value_t::discarded:
9946
0
            {
9947
0
                o->write_characters("<discarded>", 11);
9948
0
                return;
9949
4
            }
9950
4
9951
56
            case value_t::null:
9952
56
            {
9953
56
                o->write_characters("null", 4);
9954
56
                return;
9955
0
            }
9956
0
        }
9957
0
    }
9958
9959
  private:
9960
    /*!
9961
    @brief dump escaped string
9962
9963
    Escape a string by replacing certain special characters by a sequence of an
9964
    escape character (backslash) and another character and other control
9965
    characters by a sequence of "\u" followed by a four-digit hex
9966
    representation. The escaped string is written to output stream @a o.
9967
9968
    @param[in] s  the string to escape
9969
    @param[in] ensure_ascii  whether to escape non-ASCII characters with
9970
                             \uXXXX sequences
9971
9972
    @complexity Linear in the length of string @a s.
9973
    */
9974
    void dump_escaped(const string_t& s, const bool ensure_ascii)
9975
17.6k
    {
9976
17.6k
        uint32_t codepoint;
9977
17.6k
        uint8_t state = UTF8_ACCEPT;
9978
17.6k
        std::size_t bytes = 0;  // number of bytes written to string_buffer
9979
17.6k
9980
116k
        for (std::size_t i = 0; i < s.size(); ++i)
9981
98.6k
        {
9982
98.6k
            const auto byte = static_cast<uint8_t>(s[i]);
9983
98.6k
9984
98.6k
            switch (decode(state, codepoint, byte))
9985
98.6k
            {
9986
98.6k
                case UTF8_ACCEPT:  // decode found a new code point
9987
98.6k
                {
9988
98.6k
                    switch (codepoint)
9989
98.6k
                    {
9990
98.6k
                        case 0x08: // backspace
9991
0
                        {
9992
0
                            string_buffer[bytes++] = '\\';
9993
0
                            string_buffer[bytes++] = 'b';
9994
0
                            break;
9995
98.6k
                        }
9996
98.6k
9997
98.6k
                        case 0x09: // horizontal tab
9998
0
                        {
9999
0
                            string_buffer[bytes++] = '\\';
10000
0
                            string_buffer[bytes++] = 't';
10001
0
                            break;
10002
98.6k
                        }
10003
98.6k
10004
98.6k
                        case 0x0A: // newline
10005
0
                        {
10006
0
                            string_buffer[bytes++] = '\\';
10007
0
                            string_buffer[bytes++] = 'n';
10008
0
                            break;
10009
98.6k
                        }
10010
98.6k
10011
98.6k
                        case 0x0C: // formfeed
10012
0
                        {
10013
0
                            string_buffer[bytes++] = '\\';
10014
0
                            string_buffer[bytes++] = 'f';
10015
0
                            break;
10016
98.6k
                        }
10017
98.6k
10018
98.6k
                        case 0x0D: // carriage return
10019
0
                        {
10020
0
                            string_buffer[bytes++] = '\\';
10021
0
                            string_buffer[bytes++] = 'r';
10022
0
                            break;
10023
98.6k
                        }
10024
98.6k
10025
98.6k
                        case 0x22: // quotation mark
10026
0
                        {
10027
0
                            string_buffer[bytes++] = '\\';
10028
0
                            string_buffer[bytes++] = '\"';
10029
0
                            break;
10030
98.6k
                        }
10031
98.6k
10032
98.6k
                        case 0x5C: // reverse solidus
10033
0
                        {
10034
0
                            string_buffer[bytes++] = '\\';
10035
0
                            string_buffer[bytes++] = '\\';
10036
0
                            break;
10037
98.6k
                        }
10038
98.6k
10039
98.6k
                        default:
10040
98.6k
                        {
10041
98.6k
                            // escape control characters (0x00..0x1F) or, if
10042
98.6k
                            // ensure_ascii parameter is used, non-ASCII characters
10043
98.6k
                            if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F)))
10044
0
                            {
10045
0
                                if (codepoint <= 0xFFFF)
10046
0
                                {
10047
0
                                    std::snprintf(string_buffer.data() + bytes, 7, "\\u%04x",
10048
0
                                                  static_cast<uint16_t>(codepoint));
10049
0
                                    bytes += 6;
10050
0
                                }
10051
0
                                else
10052
0
                                {
10053
0
                                    std::snprintf(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
10054
0
                                                  static_cast<uint16_t>(0xD7C0 + (codepoint >> 10)),
10055
0
                                                  static_cast<uint16_t>(0xDC00 + (codepoint & 0x3FF)));
10056
0
                                    bytes += 12;
10057
0
                                }
10058
0
                            }
10059
98.6k
                            else
10060
98.6k
                            {
10061
98.6k
                                // copy byte to buffer (all previous bytes
10062
98.6k
                                // been copied have in default case above)
10063
98.6k
                                string_buffer[bytes++] = s[i];
10064
98.6k
                            }
10065
98.6k
                            break;
10066
98.6k
                        }
10067
98.6k
                    }
10068
98.6k
10069
98.6k
                    // write buffer and reset index; there must be 13 bytes
10070
98.6k
                    // left, as this is the maximal number of bytes to be
10071
98.6k
                    // written ("\uxxxx\uxxxx\0") for one code point
10072
98.6k
                    if (string_buffer.size() - bytes < 13)
10073
0
                    {
10074
0
                        o->write_characters(string_buffer.data(), bytes);
10075
0
                        bytes = 0;
10076
0
                    }
10077
98.6k
                    break;
10078
98.6k
                }
10079
98.6k
10080
98.6k
                case UTF8_REJECT:  // decode found invalid UTF-8 byte
10081
0
                {
10082
0
                    std::string sn(3, '\0');
10083
0
                    snprintf(&sn[0], sn.size(), "%.2X", byte);
10084
0
                    JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn));
10085
98.6k
                }
10086
98.6k
10087
98.6k
                default:  // decode found yet incomplete multi-byte code point
10088
0
                {
10089
0
                    if (not ensure_ascii)
10090
0
                    {
10091
0
                        // code point will not be escaped - copy byte to buffer
10092
0
                        string_buffer[bytes++] = s[i];
10093
0
                    }
10094
0
                    break;
10095
98.6k
                }
10096
98.6k
            }
10097
98.6k
        }
10098
17.6k
10099
17.6k
        if (JSON_LIKELY(state == UTF8_ACCEPT))
10100
17.6k
        {
10101
17.6k
            // write buffer
10102
17.6k
            if (bytes > 0)
10103
17.6k
            {
10104
17.6k
                o->write_characters(string_buffer.data(), bytes);
10105
17.6k
            }
10106
17.6k
        }
10107
0
        else
10108
0
        {
10109
0
            // we finish reading, but do not accept: string was incomplete
10110
0
            std::string sn(3, '\0');
10111
0
            snprintf(&sn[0], sn.size(), "%.2X", static_cast<uint8_t>(s.back()));
10112
0
            JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn));
10113
0
        }
10114
17.6k
    }
10115
10116
    /*!
10117
    @brief dump an integer
10118
10119
    Dump a given integer to output stream @a o. Works internally with
10120
    @a number_buffer.
10121
10122
    @param[in] x  integer number (signed or unsigned) to dump
10123
    @tparam NumberType either @a number_integer_t or @a number_unsigned_t
10124
    */
10125
    template<typename NumberType, detail::enable_if_t<
10126
                 std::is_same<NumberType, number_unsigned_t>::value or
10127
                 std::is_same<NumberType, number_integer_t>::value,
10128
                 int> = 0>
10129
    void dump_integer(NumberType x)
10130
1.22k
    {
10131
1.22k
        // special case for "0"
10132
1.22k
        if (x == 0)
10133
44
        {
10134
44
            o->write_character('0');
10135
44
            return;
10136
44
        }
10137
1.18k
10138
1.18k
        const bool is_negative = (x <= 0) and (x != 0);  // see issue #755
10139
1.18k
        std::size_t i = 0;
10140
1.18k
10141
3.31k
        while (x != 0)
10142
2.13k
        {
10143
2.13k
            // spare 1 byte for '\0'
10144
2.13k
            assert(i < number_buffer.size() - 1);
10145
2.13k
10146
2.13k
            const auto digit = std::labs(static_cast<long>(x % 10));
10147
2.13k
            number_buffer[i++] = static_cast<char>('0' + digit);
10148
2.13k
            x /= 10;
10149
2.13k
        }
10150
1.18k
10151
1.18k
        if (is_negative)
10152
4
        {
10153
4
            // make sure there is capacity for the '-'
10154
4
            assert(i < number_buffer.size() - 2);
10155
4
            number_buffer[i++] = '-';
10156
4
        }
10157
1.18k
10158
1.18k
        std::reverse(number_buffer.begin(), number_buffer.begin() + i);
10159
1.18k
        o->write_characters(number_buffer.data(), i);
10160
1.18k
    }
_ZN8nlohmann6detail10serializerINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12dump_integerIlLi0EEEvT_
Line
Count
Source
10130
8
    {
10131
8
        // special case for "0"
10132
8
        if (x == 0)
10133
0
        {
10134
0
            o->write_character('0');
10135
0
            return;
10136
0
        }
10137
8
10138
8
        const bool is_negative = (x <= 0) and (x != 0);  // see issue #755
10139
8
        std::size_t i = 0;
10140
8
10141
36
        while (x != 0)
10142
28
        {
10143
28
            // spare 1 byte for '\0'
10144
28
            assert(i < number_buffer.size() - 1);
10145
28
10146
28
            const auto digit = std::labs(static_cast<long>(x % 10));
10147
28
            number_buffer[i++] = static_cast<char>('0' + digit);
10148
28
            x /= 10;
10149
28
        }
10150
8
10151
8
        if (is_negative)
10152
4
        {
10153
4
            // make sure there is capacity for the '-'
10154
4
            assert(i < number_buffer.size() - 2);
10155
4
            number_buffer[i++] = '-';
10156
4
        }
10157
8
10158
8
        std::reverse(number_buffer.begin(), number_buffer.begin() + i);
10159
8
        o->write_characters(number_buffer.data(), i);
10160
8
    }
_ZN8nlohmann6detail10serializerINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEEE12dump_integerImLi0EEEvT_
Line
Count
Source
10130
1.22k
    {
10131
1.22k
        // special case for "0"
10132
1.22k
        if (x == 0)
10133
44
        {
10134
44
            o->write_character('0');
10135
44
            return;
10136
44
        }
10137
1.17k
10138
1.17k
        const bool is_negative = (x <= 0) and (x != 0);  // see issue #755
10139
1.17k
        std::size_t i = 0;
10140
1.17k
10141
3.28k
        while (x != 0)
10142
2.10k
        {
10143
2.10k
            // spare 1 byte for '\0'
10144
2.10k
            assert(i < number_buffer.size() - 1);
10145
2.10k
10146
2.10k
            const auto digit = std::labs(static_cast<long>(x % 10));
10147
2.10k
            number_buffer[i++] = static_cast<char>('0' + digit);
10148
2.10k
            x /= 10;
10149
2.10k
        }
10150
1.17k
10151
1.17k
        if (is_negative)
10152
0
        {
10153
0
            // make sure there is capacity for the '-'
10154
0
            assert(i < number_buffer.size() - 2);
10155
0
            number_buffer[i++] = '-';
10156
0
        }
10157
1.17k
10158
1.17k
        std::reverse(number_buffer.begin(), number_buffer.begin() + i);
10159
1.17k
        o->write_characters(number_buffer.data(), i);
10160
1.17k
    }
10161
10162
    /*!
10163
    @brief dump a floating-point number
10164
10165
    Dump a given floating-point number to output stream @a o. Works internally
10166
    with @a number_buffer.
10167
10168
    @param[in] x  floating-point number to dump
10169
    */
10170
    void dump_float(number_float_t x)
10171
28
    {
10172
28
        // NaN / inf
10173
28
        if (not std::isfinite(x))
10174
0
        {
10175
0
            o->write_characters("null", 4);
10176
0
            return;
10177
0
        }
10178
28
10179
28
        // If number_float_t is an IEEE-754 single or double precision number,
10180
28
        // use the Grisu2 algorithm to produce short numbers which are
10181
28
        // guaranteed to round-trip, using strtof and strtod, resp.
10182
28
        //
10183
28
        // NB: The test below works if <long double> == <double>.
10184
28
        static constexpr bool is_ieee_single_or_double
10185
28
            = (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 24 and std::numeric_limits<number_float_t>::max_exponent == 128) or
10186
28
              (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 53 and std::numeric_limits<number_float_t>::max_exponent == 1024);
10187
28
10188
28
        dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
10189
28
    }
10190
10191
    void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)
10192
28
    {
10193
28
        char* begin = number_buffer.data();
10194
28
        char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);
10195
28
10196
28
        o->write_characters(begin, static_cast<size_t>(end - begin));
10197
28
    }
10198
10199
    void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
10200
    {
10201
        // get number of digits for a float -> text -> float round-trip
10202
        static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;
10203
10204
        // the actual conversion
10205
        std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
10206
10207
        // negative value indicates an error
10208
        assert(len > 0);
10209
        // check if buffer was large enough
10210
        assert(static_cast<std::size_t>(len) < number_buffer.size());
10211
10212
        // erase thousands separator
10213
        if (thousands_sep != '\0')
10214
        {
10215
            const auto end = std::remove(number_buffer.begin(),
10216
                                         number_buffer.begin() + len, thousands_sep);
10217
            std::fill(end, number_buffer.end(), '\0');
10218
            assert((end - number_buffer.begin()) <= len);
10219
            len = (end - number_buffer.begin());
10220
        }
10221
10222
        // convert decimal point to '.'
10223
        if (decimal_point != '\0' and decimal_point != '.')
10224
        {
10225
            const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
10226
            if (dec_pos != number_buffer.end())
10227
            {
10228
                *dec_pos = '.';
10229
            }
10230
        }
10231
10232
        o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));
10233
10234
        // determine if need to append ".0"
10235
        const bool value_is_int_like =
10236
            std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,
10237
                         [](char c)
10238
        {
10239
            return (c == '.' or c == 'e');
10240
        });
10241
10242
        if (value_is_int_like)
10243
        {
10244
            o->write_characters(".0", 2);
10245
        }
10246
    }
10247
10248
    /*!
10249
    @brief check whether a string is UTF-8 encoded
10250
10251
    The function checks each byte of a string whether it is UTF-8 encoded. The
10252
    result of the check is stored in the @a state parameter. The function must
10253
    be called initially with state 0 (accept). State 1 means the string must
10254
    be rejected, because the current byte is not allowed. If the string is
10255
    completely processed, but the state is non-zero, the string ended
10256
    prematurely; that is, the last byte indicated more bytes should have
10257
    followed.
10258
10259
    @param[in,out] state  the state of the decoding
10260
    @param[in,out] codep  codepoint (valid only if resulting state is UTF8_ACCEPT)
10261
    @param[in] byte       next byte to decode
10262
    @return               new state
10263
10264
    @note The function has been edited: a std::array is used.
10265
10266
    @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
10267
    @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
10268
    */
10269
    static uint8_t decode(uint8_t& state, uint32_t& codep, const uint8_t byte) noexcept
10270
98.6k
    {
10271
98.6k
        static const std::array<uint8_t, 400> utf8d =
10272
98.6k
        {
10273
98.6k
            {
10274
98.6k
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F
10275
98.6k
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F
10276
98.6k
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F
10277
98.6k
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F
10278
98.6k
                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F
10279
98.6k
                7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF
10280
98.6k
                8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF
10281
98.6k
                0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF
10282
98.6k
                0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF
10283
98.6k
                0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
10284
98.6k
                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
10285
98.6k
                1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
10286
98.6k
                1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
10287
98.6k
                1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8
10288
98.6k
            }
10289
98.6k
        };
10290
98.6k
10291
98.6k
        const uint8_t type = utf8d[byte];
10292
98.6k
10293
98.6k
        codep = (state != UTF8_ACCEPT)
10294
98.6k
                ? (byte & 0x3fu) | (codep << 6)
10295
98.6k
                : static_cast<uint32_t>(0xff >> type) & (byte);
10296
98.6k
10297
98.6k
        state = utf8d[256u + state * 16u + type];
10298
98.6k
        return state;
10299
98.6k
    }
10300
10301
  private:
10302
    /// the output of the serializer
10303
    output_adapter_t<char> o = nullptr;
10304
10305
    /// a (hopefully) large enough character buffer
10306
    std::array<char, 64> number_buffer{{}};
10307
10308
    /// the locale
10309
    const std::lconv* loc = nullptr;
10310
    /// the locale's thousand separator character
10311
    const char thousands_sep = '\0';
10312
    /// the locale's decimal point character
10313
    const char decimal_point = '\0';
10314
10315
    /// string buffer
10316
    std::array<char, 512> string_buffer{{}};
10317
10318
    /// the indentation character
10319
    const char indent_char;
10320
    /// the indentation string
10321
    string_t indent_string;
10322
};
10323
}
10324
}
10325
10326
// #include <nlohmann/detail/json_ref.hpp>
10327
10328
10329
#include <initializer_list>
10330
#include <utility>
10331
10332
namespace nlohmann
10333
{
10334
namespace detail
10335
{
10336
template<typename BasicJsonType>
10337
class json_ref
10338
{
10339
  public:
10340
    using value_type = BasicJsonType;
10341
10342
    json_ref(value_type&& value)
10343
        : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true)
10344
    {}
10345
10346
    json_ref(const value_type& value)
10347
        : value_ref(const_cast<value_type*>(&value)), is_rvalue(false)
10348
    {}
10349
10350
    json_ref(std::initializer_list<json_ref> init)
10351
        : owned_value(init), value_ref(&owned_value), is_rvalue(true)
10352
    {}
10353
10354
    template<class... Args>
10355
    json_ref(Args&& ... args)
10356
        : owned_value(std::forward<Args>(args)...), value_ref(&owned_value), is_rvalue(true)
10357
    {}
10358
10359
    // class should be movable only
10360
    json_ref(json_ref&&) = default;
10361
    json_ref(const json_ref&) = delete;
10362
    json_ref& operator=(const json_ref&) = delete;
10363
10364
    value_type moved_or_copied() const
10365
    {
10366
        if (is_rvalue)
10367
        {
10368
            return std::move(*value_ref);
10369
        }
10370
        return *value_ref;
10371
    }
10372
10373
    value_type const& operator*() const
10374
    {
10375
        return *static_cast<value_type const*>(value_ref);
10376
    }
10377
10378
    value_type const* operator->() const
10379
    {
10380
        return static_cast<value_type const*>(value_ref);
10381
    }
10382
10383
  private:
10384
    mutable value_type owned_value = nullptr;
10385
    value_type* value_ref = nullptr;
10386
    const bool is_rvalue;
10387
};
10388
}
10389
}
10390
10391
// #include <nlohmann/detail/json_pointer.hpp>
10392
10393
10394
#include <cassert> // assert
10395
#include <numeric> // accumulate
10396
#include <string> // string
10397
#include <vector> // vector
10398
10399
// #include <nlohmann/detail/macro_scope.hpp>
10400
10401
// #include <nlohmann/detail/exceptions.hpp>
10402
10403
// #include <nlohmann/detail/value_t.hpp>
10404
10405
10406
namespace nlohmann
10407
{
10408
template<typename BasicJsonType>
10409
class json_pointer
10410
{
10411
    // allow basic_json to access private members
10412
    NLOHMANN_BASIC_JSON_TPL_DECLARATION
10413
    friend class basic_json;
10414
10415
  public:
10416
    /*!
10417
    @brief create JSON pointer
10418
10419
    Create a JSON pointer according to the syntax described in
10420
    [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).
10421
10422
    @param[in] s  string representing the JSON pointer; if omitted, the empty
10423
                  string is assumed which references the whole JSON value
10424
10425
    @throw parse_error.107 if the given JSON pointer @a s is nonempty and does
10426
                           not begin with a slash (`/`); see example below
10427
10428
    @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is
10429
    not followed by `0` (representing `~`) or `1` (representing `/`); see
10430
    example below
10431
10432
    @liveexample{The example shows the construction several valid JSON pointers
10433
    as well as the exceptional behavior.,json_pointer}
10434
10435
    @since version 2.0.0
10436
    */
10437
    explicit json_pointer(const std::string& s = "")
10438
        : reference_tokens(split(s))
10439
    {}
10440
10441
    /*!
10442
    @brief return a string representation of the JSON pointer
10443
10444
    @invariant For each JSON pointer `ptr`, it holds:
10445
    @code {.cpp}
10446
    ptr == json_pointer(ptr.to_string());
10447
    @endcode
10448
10449
    @return a string representation of the JSON pointer
10450
10451
    @liveexample{The example shows the result of `to_string`.,
10452
    json_pointer__to_string}
10453
10454
    @since version 2.0.0
10455
    */
10456
    std::string to_string() const noexcept
10457
    {
10458
        return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
10459
                               std::string{},
10460
                               [](const std::string & a, const std::string & b)
10461
        {
10462
            return a + "/" + escape(b);
10463
        });
10464
    }
10465
10466
    /// @copydoc to_string()
10467
    operator std::string() const
10468
    {
10469
        return to_string();
10470
    }
10471
10472
    /*!
10473
    @param[in] s  reference token to be converted into an array index
10474
10475
    @return integer representation of @a s
10476
10477
    @throw out_of_range.404 if string @a s could not be converted to an integer
10478
    */
10479
    static int array_index(const std::string& s)
10480
    {
10481
        std::size_t processed_chars = 0;
10482
        const int res = std::stoi(s, &processed_chars);
10483
10484
        // check if the string was completely read
10485
        if (JSON_UNLIKELY(processed_chars != s.size()))
10486
        {
10487
            JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'"));
10488
        }
10489
10490
        return res;
10491
    }
10492
10493
  private:
10494
    /*!
10495
    @brief remove and return last reference pointer
10496
    @throw out_of_range.405 if JSON pointer has no parent
10497
    */
10498
    std::string pop_back()
10499
    {
10500
        if (JSON_UNLIKELY(is_root()))
10501
        {
10502
            JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
10503
        }
10504
10505
        auto last = reference_tokens.back();
10506
        reference_tokens.pop_back();
10507
        return last;
10508
    }
10509
10510
    /// return whether pointer points to the root document
10511
    bool is_root() const
10512
    {
10513
        return reference_tokens.empty();
10514
    }
10515
10516
    json_pointer top() const
10517
    {
10518
        if (JSON_UNLIKELY(is_root()))
10519
        {
10520
            JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
10521
        }
10522
10523
        json_pointer result = *this;
10524
        result.reference_tokens = {reference_tokens[0]};
10525
        return result;
10526
    }
10527
10528
    /*!
10529
    @brief create and return a reference to the pointed to value
10530
10531
    @complexity Linear in the number of reference tokens.
10532
10533
    @throw parse_error.109 if array index is not a number
10534
    @throw type_error.313 if value cannot be unflattened
10535
    */
10536
    BasicJsonType& get_and_create(BasicJsonType& j) const
10537
    {
10538
        using size_type = typename BasicJsonType::size_type;
10539
        auto result = &j;
10540
10541
        // in case no reference tokens exist, return a reference to the JSON value
10542
        // j which will be overwritten by a primitive value
10543
        for (const auto& reference_token : reference_tokens)
10544
        {
10545
            switch (result->m_type)
10546
            {
10547
                case detail::value_t::null:
10548
                {
10549
                    if (reference_token == "0")
10550
                    {
10551
                        // start a new array if reference token is 0
10552
                        result = &result->operator[](0);
10553
                    }
10554
                    else
10555
                    {
10556
                        // start a new object otherwise
10557
                        result = &result->operator[](reference_token);
10558
                    }
10559
                    break;
10560
                }
10561
10562
                case detail::value_t::object:
10563
                {
10564
                    // create an entry in the object
10565
                    result = &result->operator[](reference_token);
10566
                    break;
10567
                }
10568
10569
                case detail::value_t::array:
10570
                {
10571
                    // create an entry in the array
10572
                    JSON_TRY
10573
                    {
10574
                        result = &result->operator[](static_cast<size_type>(array_index(reference_token)));
10575
                    }
10576
                    JSON_CATCH(std::invalid_argument&)
10577
                    {
10578
                        JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
10579
                    }
10580
                    break;
10581
                }
10582
10583
                /*
10584
                The following code is only reached if there exists a reference
10585
                token _and_ the current value is primitive. In this case, we have
10586
                an error situation, because primitive values may only occur as
10587
                single value; that is, with an empty list of reference tokens.
10588
                */
10589
                default:
10590
                    JSON_THROW(detail::type_error::create(313, "invalid value to unflatten"));
10591
            }
10592
        }
10593
10594
        return *result;
10595
    }
10596
10597
    /*!
10598
    @brief return a reference to the pointed to value
10599
10600
    @note This version does not throw if a value is not present, but tries to
10601
          create nested values instead. For instance, calling this function
10602
          with pointer `"/this/that"` on a null value is equivalent to calling
10603
          `operator[]("this").operator[]("that")` on that value, effectively
10604
          changing the null value to an object.
10605
10606
    @param[in] ptr  a JSON value
10607
10608
    @return reference to the JSON value pointed to by the JSON pointer
10609
10610
    @complexity Linear in the length of the JSON pointer.
10611
10612
    @throw parse_error.106   if an array index begins with '0'
10613
    @throw parse_error.109   if an array index was not a number
10614
    @throw out_of_range.404  if the JSON pointer can not be resolved
10615
    */
10616
    BasicJsonType& get_unchecked(BasicJsonType* ptr) const
10617
    {
10618
        using size_type = typename BasicJsonType::size_type;
10619
        for (const auto& reference_token : reference_tokens)
10620
        {
10621
            // convert null values to arrays or objects before continuing
10622
            if (ptr->m_type == detail::value_t::null)
10623
            {
10624
                // check if reference token is a number
10625
                const bool nums =
10626
                    std::all_of(reference_token.begin(), reference_token.end(),
10627
                                [](const char x)
10628
                {
10629
                    return (x >= '0' and x <= '9');
10630
                });
10631
10632
                // change value to array for numbers or "-" or to object otherwise
10633
                *ptr = (nums or reference_token == "-")
10634
                       ? detail::value_t::array
10635
                       : detail::value_t::object;
10636
            }
10637
10638
            switch (ptr->m_type)
10639
            {
10640
                case detail::value_t::object:
10641
                {
10642
                    // use unchecked object access
10643
                    ptr = &ptr->operator[](reference_token);
10644
                    break;
10645
                }
10646
10647
                case detail::value_t::array:
10648
                {
10649
                    // error condition (cf. RFC 6901, Sect. 4)
10650
                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
10651
                    {
10652
                        JSON_THROW(detail::parse_error::create(106, 0,
10653
                                                               "array index '" + reference_token +
10654
                                                               "' must not begin with '0'"));
10655
                    }
10656
10657
                    if (reference_token == "-")
10658
                    {
10659
                        // explicitly treat "-" as index beyond the end
10660
                        ptr = &ptr->operator[](ptr->m_value.array->size());
10661
                    }
10662
                    else
10663
                    {
10664
                        // convert array index to number; unchecked access
10665
                        JSON_TRY
10666
                        {
10667
                            ptr = &ptr->operator[](
10668
                                static_cast<size_type>(array_index(reference_token)));
10669
                        }
10670
                        JSON_CATCH(std::invalid_argument&)
10671
                        {
10672
                            JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
10673
                        }
10674
                    }
10675
                    break;
10676
                }
10677
10678
                default:
10679
                    JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
10680
            }
10681
        }
10682
10683
        return *ptr;
10684
    }
10685
10686
    /*!
10687
    @throw parse_error.106   if an array index begins with '0'
10688
    @throw parse_error.109   if an array index was not a number
10689
    @throw out_of_range.402  if the array index '-' is used
10690
    @throw out_of_range.404  if the JSON pointer can not be resolved
10691
    */
10692
    BasicJsonType& get_checked(BasicJsonType* ptr) const
10693
    {
10694
        using size_type = typename BasicJsonType::size_type;
10695
        for (const auto& reference_token : reference_tokens)
10696
        {
10697
            switch (ptr->m_type)
10698
            {
10699
                case detail::value_t::object:
10700
                {
10701
                    // note: at performs range check
10702
                    ptr = &ptr->at(reference_token);
10703
                    break;
10704
                }
10705
10706
                case detail::value_t::array:
10707
                {
10708
                    if (JSON_UNLIKELY(reference_token == "-"))
10709
                    {
10710
                        // "-" always fails the range check
10711
                        JSON_THROW(detail::out_of_range::create(402,
10712
                                                                "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
10713
                                                                ") is out of range"));
10714
                    }
10715
10716
                    // error condition (cf. RFC 6901, Sect. 4)
10717
                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
10718
                    {
10719
                        JSON_THROW(detail::parse_error::create(106, 0,
10720
                                                               "array index '" + reference_token +
10721
                                                               "' must not begin with '0'"));
10722
                    }
10723
10724
                    // note: at performs range check
10725
                    JSON_TRY
10726
                    {
10727
                        ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));
10728
                    }
10729
                    JSON_CATCH(std::invalid_argument&)
10730
                    {
10731
                        JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
10732
                    }
10733
                    break;
10734
                }
10735
10736
                default:
10737
                    JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
10738
            }
10739
        }
10740
10741
        return *ptr;
10742
    }
10743
10744
    /*!
10745
    @brief return a const reference to the pointed to value
10746
10747
    @param[in] ptr  a JSON value
10748
10749
    @return const reference to the JSON value pointed to by the JSON
10750
    pointer
10751
10752
    @throw parse_error.106   if an array index begins with '0'
10753
    @throw parse_error.109   if an array index was not a number
10754
    @throw out_of_range.402  if the array index '-' is used
10755
    @throw out_of_range.404  if the JSON pointer can not be resolved
10756
    */
10757
    const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
10758
    {
10759
        using size_type = typename BasicJsonType::size_type;
10760
        for (const auto& reference_token : reference_tokens)
10761
        {
10762
            switch (ptr->m_type)
10763
            {
10764
                case detail::value_t::object:
10765
                {
10766
                    // use unchecked object access
10767
                    ptr = &ptr->operator[](reference_token);
10768
                    break;
10769
                }
10770
10771
                case detail::value_t::array:
10772
                {
10773
                    if (JSON_UNLIKELY(reference_token == "-"))
10774
                    {
10775
                        // "-" cannot be used for const access
10776
                        JSON_THROW(detail::out_of_range::create(402,
10777
                                                                "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
10778
                                                                ") is out of range"));
10779
                    }
10780
10781
                    // error condition (cf. RFC 6901, Sect. 4)
10782
                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
10783
                    {
10784
                        JSON_THROW(detail::parse_error::create(106, 0,
10785
                                                               "array index '" + reference_token +
10786
                                                               "' must not begin with '0'"));
10787
                    }
10788
10789
                    // use unchecked array access
10790
                    JSON_TRY
10791
                    {
10792
                        ptr = &ptr->operator[](
10793
                            static_cast<size_type>(array_index(reference_token)));
10794
                    }
10795
                    JSON_CATCH(std::invalid_argument&)
10796
                    {
10797
                        JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
10798
                    }
10799
                    break;
10800
                }
10801
10802
                default:
10803
                    JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
10804
            }
10805
        }
10806
10807
        return *ptr;
10808
    }
10809
10810
    /*!
10811
    @throw parse_error.106   if an array index begins with '0'
10812
    @throw parse_error.109   if an array index was not a number
10813
    @throw out_of_range.402  if the array index '-' is used
10814
    @throw out_of_range.404  if the JSON pointer can not be resolved
10815
    */
10816
    const BasicJsonType& get_checked(const BasicJsonType* ptr) const
10817
    {
10818
        using size_type = typename BasicJsonType::size_type;
10819
        for (const auto& reference_token : reference_tokens)
10820
        {
10821
            switch (ptr->m_type)
10822
            {
10823
                case detail::value_t::object:
10824
                {
10825
                    // note: at performs range check
10826
                    ptr = &ptr->at(reference_token);
10827
                    break;
10828
                }
10829
10830
                case detail::value_t::array:
10831
                {
10832
                    if (JSON_UNLIKELY(reference_token == "-"))
10833
                    {
10834
                        // "-" always fails the range check
10835
                        JSON_THROW(detail::out_of_range::create(402,
10836
                                                                "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
10837
                                                                ") is out of range"));
10838
                    }
10839
10840
                    // error condition (cf. RFC 6901, Sect. 4)
10841
                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
10842
                    {
10843
                        JSON_THROW(detail::parse_error::create(106, 0,
10844
                                                               "array index '" + reference_token +
10845
                                                               "' must not begin with '0'"));
10846
                    }
10847
10848
                    // note: at performs range check
10849
                    JSON_TRY
10850
                    {
10851
                        ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));
10852
                    }
10853
                    JSON_CATCH(std::invalid_argument&)
10854
                    {
10855
                        JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
10856
                    }
10857
                    break;
10858
                }
10859
10860
                default:
10861
                    JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
10862
            }
10863
        }
10864
10865
        return *ptr;
10866
    }
10867
10868
    /*!
10869
    @brief split the string input to reference tokens
10870
10871
    @note This function is only called by the json_pointer constructor.
10872
          All exceptions below are documented there.
10873
10874
    @throw parse_error.107  if the pointer is not empty or begins with '/'
10875
    @throw parse_error.108  if character '~' is not followed by '0' or '1'
10876
    */
10877
    static std::vector<std::string> split(const std::string& reference_string)
10878
0
    {
10879
0
        std::vector<std::string> result;
10880
0
10881
0
        // special case: empty reference string -> no reference tokens
10882
0
        if (reference_string.empty())
10883
0
        {
10884
0
            return result;
10885
0
        }
10886
0
10887
0
        // check if nonempty reference string begins with slash
10888
0
        if (JSON_UNLIKELY(reference_string[0] != '/'))
10889
0
        {
10890
0
            JSON_THROW(detail::parse_error::create(107, 1,
10891
0
                                                   "JSON pointer must be empty or begin with '/' - was: '" +
10892
0
                                                   reference_string + "'"));
10893
0
        }
10894
0
10895
0
        // extract the reference tokens:
10896
0
        // - slash: position of the last read slash (or end of string)
10897
0
        // - start: position after the previous slash
10898
0
        for (
10899
0
            // search for the first slash after the first character
10900
0
            std::size_t slash = reference_string.find_first_of('/', 1),
10901
0
            // set the beginning of the first reference token
10902
0
            start = 1;
10903
0
            // we can stop if start == string::npos+1 = 0
10904
0
            start != 0;
10905
0
            // set the beginning of the next reference token
10906
0
            // (will eventually be 0 if slash == std::string::npos)
10907
0
            start = slash + 1,
10908
0
            // find next slash
10909
0
            slash = reference_string.find_first_of('/', start))
10910
0
        {
10911
0
            // use the text between the beginning of the reference token
10912
0
            // (start) and the last slash (slash).
10913
0
            auto reference_token = reference_string.substr(start, slash - start);
10914
0
10915
0
            // check reference tokens are properly escaped
10916
0
            for (std::size_t pos = reference_token.find_first_of('~');
10917
0
                    pos != std::string::npos;
10918
0
                    pos = reference_token.find_first_of('~', pos + 1))
10919
0
            {
10920
0
                assert(reference_token[pos] == '~');
10921
0
10922
0
                // ~ must be followed by 0 or 1
10923
0
                if (JSON_UNLIKELY(pos == reference_token.size() - 1 or
10924
0
                                  (reference_token[pos + 1] != '0' and
10925
0
                                   reference_token[pos + 1] != '1')))
10926
0
                {
10927
0
                    JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'"));
10928
0
                }
10929
0
            }
10930
0
10931
0
            // finally, store the reference token
10932
0
            unescape(reference_token);
10933
0
            result.push_back(reference_token);
10934
0
        }
10935
0
10936
0
        return result;
10937
0
    }
10938
10939
    /*!
10940
    @brief replace all occurrences of a substring by another string
10941
10942
    @param[in,out] s  the string to manipulate; changed so that all
10943
                   occurrences of @a f are replaced with @a t
10944
    @param[in]     f  the substring to replace with @a t
10945
    @param[in]     t  the string to replace @a f
10946
10947
    @pre The search string @a f must not be empty. **This precondition is
10948
    enforced with an assertion.**
10949
10950
    @since version 2.0.0
10951
    */
10952
    static void replace_substring(std::string& s, const std::string& f,
10953
                                  const std::string& t)
10954
0
    {
10955
0
        assert(not f.empty());
10956
0
        for (auto pos = s.find(f);                // find first occurrence of f
10957
0
                pos != std::string::npos;         // make sure f was found
10958
0
                s.replace(pos, f.size(), t),      // replace with t, and
10959
0
                pos = s.find(f, pos + t.size()))  // find next occurrence of f
10960
0
        {}
10961
0
    }
10962
10963
    /// escape "~"" to "~0" and "/" to "~1"
10964
    static std::string escape(std::string s)
10965
    {
10966
        replace_substring(s, "~", "~0");
10967
        replace_substring(s, "/", "~1");
10968
        return s;
10969
    }
10970
10971
    /// unescape "~1" to tilde and "~0" to slash (order is important!)
10972
    static void unescape(std::string& s)
10973
0
    {
10974
0
        replace_substring(s, "~1", "/");
10975
0
        replace_substring(s, "~0", "~");
10976
0
    }
10977
10978
    /*!
10979
    @param[in] reference_string  the reference string to the current value
10980
    @param[in] value             the value to consider
10981
    @param[in,out] result        the result object to insert values to
10982
10983
    @note Empty objects or arrays are flattened to `null`.
10984
    */
10985
    static void flatten(const std::string& reference_string,
10986
                        const BasicJsonType& value,
10987
                        BasicJsonType& result)
10988
    {
10989
        switch (value.m_type)
10990
        {
10991
            case detail::value_t::array:
10992
            {
10993
                if (value.m_value.array->empty())
10994
                {
10995
                    // flatten empty array as null
10996
                    result[reference_string] = nullptr;
10997
                }
10998
                else
10999
                {
11000
                    // iterate array and use index as reference string
11001
                    for (std::size_t i = 0; i < value.m_value.array->size(); ++i)
11002
                    {
11003
                        flatten(reference_string + "/" + std::to_string(i),
11004
                                value.m_value.array->operator[](i), result);
11005
                    }
11006
                }
11007
                break;
11008
            }
11009
11010
            case detail::value_t::object:
11011
            {
11012
                if (value.m_value.object->empty())
11013
                {
11014
                    // flatten empty object as null
11015
                    result[reference_string] = nullptr;
11016
                }
11017
                else
11018
                {
11019
                    // iterate object and use keys as reference string
11020
                    for (const auto& element : *value.m_value.object)
11021
                    {
11022
                        flatten(reference_string + "/" + escape(element.first), element.second, result);
11023
                    }
11024
                }
11025
                break;
11026
            }
11027
11028
            default:
11029
            {
11030
                // add primitive value with its reference string
11031
                result[reference_string] = value;
11032
                break;
11033
            }
11034
        }
11035
    }
11036
11037
    /*!
11038
    @param[in] value  flattened JSON
11039
11040
    @return unflattened JSON
11041
11042
    @throw parse_error.109 if array index is not a number
11043
    @throw type_error.314  if value is not an object
11044
    @throw type_error.315  if object values are not primitive
11045
    @throw type_error.313  if value cannot be unflattened
11046
    */
11047
    static BasicJsonType
11048
    unflatten(const BasicJsonType& value)
11049
    {
11050
        if (JSON_UNLIKELY(not value.is_object()))
11051
        {
11052
            JSON_THROW(detail::type_error::create(314, "only objects can be unflattened"));
11053
        }
11054
11055
        BasicJsonType result;
11056
11057
        // iterate the JSON object values
11058
        for (const auto& element : *value.m_value.object)
11059
        {
11060
            if (JSON_UNLIKELY(not element.second.is_primitive()))
11061
            {
11062
                JSON_THROW(detail::type_error::create(315, "values in object must be primitive"));
11063
            }
11064
11065
            // assign value to reference pointed to by JSON pointer; Note that if
11066
            // the JSON pointer is "" (i.e., points to the whole value), function
11067
            // get_and_create returns a reference to result itself. An assignment
11068
            // will then create a primitive value.
11069
            json_pointer(element.first).get_and_create(result) = element.second;
11070
        }
11071
11072
        return result;
11073
    }
11074
11075
    friend bool operator==(json_pointer const& lhs,
11076
                           json_pointer const& rhs) noexcept
11077
    {
11078
        return (lhs.reference_tokens == rhs.reference_tokens);
11079
    }
11080
11081
    friend bool operator!=(json_pointer const& lhs,
11082
                           json_pointer const& rhs) noexcept
11083
    {
11084
        return not (lhs == rhs);
11085
    }
11086
11087
    /// the reference tokens
11088
    std::vector<std::string> reference_tokens;
11089
};
11090
}
11091
11092
// #include <nlohmann/adl_serializer.hpp>
11093
11094
11095
#include <utility>
11096
11097
// #include <nlohmann/detail/conversions/from_json.hpp>
11098
11099
// #include <nlohmann/detail/conversions/to_json.hpp>
11100
11101
11102
namespace nlohmann
11103
{
11104
template<typename, typename>
11105
struct adl_serializer
11106
{
11107
    /*!
11108
    @brief convert a JSON value to any value type
11109
11110
    This function is usually called by the `get()` function of the
11111
    @ref basic_json class (either explicit or via conversion operators).
11112
11113
    @param[in] j         JSON value to read from
11114
    @param[in,out] val  value to write to
11115
    */
11116
    template<typename BasicJsonType, typename ValueType>
11117
    static auto from_json(BasicJsonType&& j, ValueType& val) noexcept(
11118
        noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) -> decltype(
11119
            ::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void()
11120
        )
11121
47.7k
    {
11122
47.7k
        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
11123
47.7k
    }
_ZN8nlohmann14adl_serializerIbvE9from_jsonIRKNS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EEbEEDTcmclL_ZNS_12_GLOBAL__N_19from_jsonEEclsr3stdE7forwardIT_Efp_Efp0_Ecvv_EEOSG_RT0_
Line
Count
Source
11121
8
    {
11122
8
        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
11123
8
    }
_ZN8nlohmann14adl_serializerINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEvE9from_jsonIRKNS_10basic_jsonISt3mapSt6vectorS6_blmdSaS0_EES6_EEDTcmclL_ZNS_12_GLOBAL__N_19from_jsonEEclsr3stdE7forwardIT_Efp_Efp0_Ecvv_EEOSG_RT0_
Line
Count
Source
11121
46.5k
    {
11122
46.5k
        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
11123
46.5k
    }
_ZN8nlohmann14adl_serializerIivE9from_jsonIRKNS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EEiEEDTcmclL_ZNS_12_GLOBAL__N_19from_jsonEEclsr3stdE7forwardIT_Efp_Efp0_Ecvv_EEOSG_RT0_
Line
Count
Source
11121
608
    {
11122
608
        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
11123
608
    }
_ZN8nlohmann14adl_serializerIdvE9from_jsonIRKNS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EEdEEDTcmclL_ZNS_12_GLOBAL__N_19from_jsonEEclsr3stdE7forwardIT_Efp_Efp0_Ecvv_EEOSG_RT0_
Line
Count
Source
11121
592
    {
11122
592
        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
11123
592
    }
11124
11125
    /*!
11126
    @brief convert any value type to a JSON value
11127
11128
    This function is usually called by the constructors of the @ref basic_json
11129
    class.
11130
11131
    @param[in,out] j  JSON value to write to
11132
    @param[in] val     value to read from
11133
    */
11134
    template <typename BasicJsonType, typename ValueType>
11135
    static auto to_json(BasicJsonType& j, ValueType&& val) noexcept(
11136
        noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val))))
11137
    -> decltype(::nlohmann::to_json(j, std::forward<ValueType>(val)),
11138
                void())
11139
847k
    {
11140
847k
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
11141
847k
    }
_ZN8nlohmann14adl_serializerINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEvE7to_jsonINS_10basic_jsonISt3mapSt6vectorS6_blmdSaS0_EERS6_EEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
Line
Count
Source
11139
255k
    {
11140
255k
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
11141
255k
    }
_ZN8nlohmann14adl_serializerIdvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERdEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
Line
Count
Source
11139
234k
    {
11140
234k
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
11141
234k
    }
_ZN8nlohmann14adl_serializerIbvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERbEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
Line
Count
Source
11139
2.45k
    {
11140
2.45k
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
11141
2.45k
    }
_ZN8nlohmann14adl_serializerIlvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERlEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
Line
Count
Source
11139
37.4k
    {
11140
37.4k
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
11141
37.4k
    }
_ZN8nlohmann14adl_serializerImvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERmEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
Line
Count
Source
11139
314k
    {
11140
314k
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
11141
314k
    }
_ZN8nlohmann14adl_serializerIA474_cvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERA474_KcEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSI_
Line
Count
Source
11139
812
    {
11140
812
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
11141
812
    }
_ZN8nlohmann14adl_serializerINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEvE7to_jsonINS_10basic_jsonISt3mapSt6vectorS6_blmdSaS0_EES6_EEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
Line
Count
Source
11139
1.76k
    {
11140
1.76k
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
11141
1.76k
    }
_ZN8nlohmann14adl_serializerINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEvE7to_jsonINS_10basic_jsonISt3mapSt6vectorS6_blmdSaS0_EEKS6_EEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
Line
Count
Source
11139
196
    {
11140
196
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
11141
196
    }
_ZN8nlohmann14adl_serializerIjvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERjEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSF_
Line
Count
Source
11139
588
    {
11140
588
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
11141
588
    }
_ZN8nlohmann14adl_serializerIPKcvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERKS2_EEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSI_
Line
Count
Source
11139
40
    {
11140
40
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
11141
40
    }
_ZN8nlohmann14adl_serializerIbvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EEbEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
Line
Count
Source
11139
4
    {
11140
4
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
11141
4
    }
_ZN8nlohmann14adl_serializerIdvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EEdEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
Line
Count
Source
11139
4
    {
11140
4
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
11141
4
    }
_ZN8nlohmann14adl_serializerIA6_cvE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EERA6_KcEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSI_
Line
Count
Source
11139
4
    {
11140
4
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
11141
4
    }
_ZN8nlohmann14adl_serializerIivE7to_jsonINS_10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaS0_EEiEEDTcmclL_ZNS_12_GLOBAL__N_17to_jsonEEfp_clsr3stdE7forwardIT0_Efp0_EEcvv_EERT_OSE_
Line
Count
Source
11139
4
    {
11140
4
        ::nlohmann::to_json(j, std::forward<ValueType>(val));
11141
4
    }
11142
};
11143
}
11144
11145
11146
/*!
11147
@brief namespace for Niels Lohmann
11148
@see https://github.com/nlohmann
11149
@since version 1.0.0
11150
*/
11151
namespace nlohmann
11152
{
11153
11154
/*!
11155
@brief a class to store JSON values
11156
11157
@tparam ObjectType type for JSON objects (`std::map` by default; will be used
11158
in @ref object_t)
11159
@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used
11160
in @ref array_t)
11161
@tparam StringType type for JSON strings and object keys (`std::string` by
11162
default; will be used in @ref string_t)
11163
@tparam BooleanType type for JSON booleans (`bool` by default; will be used
11164
in @ref boolean_t)
11165
@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by
11166
default; will be used in @ref number_integer_t)
11167
@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c
11168
`uint64_t` by default; will be used in @ref number_unsigned_t)
11169
@tparam NumberFloatType type for JSON floating-point numbers (`double` by
11170
default; will be used in @ref number_float_t)
11171
@tparam AllocatorType type of the allocator to use (`std::allocator` by
11172
default)
11173
@tparam JSONSerializer the serializer to resolve internal calls to `to_json()`
11174
and `from_json()` (@ref adl_serializer by default)
11175
11176
@requirement The class satisfies the following concept requirements:
11177
- Basic
11178
 - [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible):
11179
   JSON values can be default constructed. The result will be a JSON null
11180
   value.
11181
 - [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible):
11182
   A JSON value can be constructed from an rvalue argument.
11183
 - [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible):
11184
   A JSON value can be copy-constructed from an lvalue expression.
11185
 - [MoveAssignable](https://en.cppreference.com/w/cpp/named_req/MoveAssignable):
11186
   A JSON value van be assigned from an rvalue argument.
11187
 - [CopyAssignable](https://en.cppreference.com/w/cpp/named_req/CopyAssignable):
11188
   A JSON value can be copy-assigned from an lvalue expression.
11189
 - [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible):
11190
   JSON values can be destructed.
11191
- Layout
11192
 - [StandardLayoutType](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType):
11193
   JSON values have
11194
   [standard layout](https://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
11195
   All non-static data members are private and standard layout types, the
11196
   class has no virtual functions or (virtual) base classes.
11197
- Library-wide
11198
 - [EqualityComparable](https://en.cppreference.com/w/cpp/named_req/EqualityComparable):
11199
   JSON values can be compared with `==`, see @ref
11200
   operator==(const_reference,const_reference).
11201
 - [LessThanComparable](https://en.cppreference.com/w/cpp/named_req/LessThanComparable):
11202
   JSON values can be compared with `<`, see @ref
11203
   operator<(const_reference,const_reference).
11204
 - [Swappable](https://en.cppreference.com/w/cpp/named_req/Swappable):
11205
   Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of
11206
   other compatible types, using unqualified function call @ref swap().
11207
 - [NullablePointer](https://en.cppreference.com/w/cpp/named_req/NullablePointer):
11208
   JSON values can be compared against `std::nullptr_t` objects which are used
11209
   to model the `null` value.
11210
- Container
11211
 - [Container](https://en.cppreference.com/w/cpp/named_req/Container):
11212
   JSON values can be used like STL containers and provide iterator access.
11213
 - [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer);
11214
   JSON values can be used like STL containers and provide reverse iterator
11215
   access.
11216
11217
@invariant The member variables @a m_value and @a m_type have the following
11218
relationship:
11219
- If `m_type == value_t::object`, then `m_value.object != nullptr`.
11220
- If `m_type == value_t::array`, then `m_value.array != nullptr`.
11221
- If `m_type == value_t::string`, then `m_value.string != nullptr`.
11222
The invariants are checked by member function assert_invariant().
11223
11224
@internal
11225
@note ObjectType trick from http://stackoverflow.com/a/9860911
11226
@endinternal
11227
11228
@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange
11229
Format](http://rfc7159.net/rfc7159)
11230
11231
@since version 1.0.0
11232
11233
@nosubgrouping
11234
*/
11235
NLOHMANN_BASIC_JSON_TPL_DECLARATION
11236
class basic_json
11237
{
11238
  private:
11239
    template<detail::value_t> friend struct detail::external_constructor;
11240
    friend ::nlohmann::json_pointer<basic_json>;
11241
    friend ::nlohmann::detail::parser<basic_json>;
11242
    friend ::nlohmann::detail::serializer<basic_json>;
11243
    template<typename BasicJsonType>
11244
    friend class ::nlohmann::detail::iter_impl;
11245
    template<typename BasicJsonType, typename CharType>
11246
    friend class ::nlohmann::detail::binary_writer;
11247
    template<typename BasicJsonType, typename SAX>
11248
    friend class ::nlohmann::detail::binary_reader;
11249
    template<typename BasicJsonType>
11250
    friend class ::nlohmann::detail::json_sax_dom_parser;
11251
    template<typename BasicJsonType>
11252
    friend class ::nlohmann::detail::json_sax_dom_callback_parser;
11253
11254
    /// workaround type for MSVC
11255
    using basic_json_t = NLOHMANN_BASIC_JSON_TPL;
11256
11257
    // convenience aliases for types residing in namespace detail;
11258
    using lexer = ::nlohmann::detail::lexer<basic_json>;
11259
    using parser = ::nlohmann::detail::parser<basic_json>;
11260
11261
    using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;
11262
    template<typename BasicJsonType>
11263
    using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>;
11264
    template<typename BasicJsonType>
11265
    using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>;
11266
    template<typename Iterator>
11267
    using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;
11268
    template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;
11269
11270
    template<typename CharType>
11271
    using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;
11272
11273
    using binary_reader = ::nlohmann::detail::binary_reader<basic_json>;
11274
    template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;
11275
11276
    using serializer = ::nlohmann::detail::serializer<basic_json>;
11277
11278
  public:
11279
    using value_t = detail::value_t;
11280
    /// JSON Pointer, see @ref nlohmann::json_pointer
11281
    using json_pointer = ::nlohmann::json_pointer<basic_json>;
11282
    template<typename T, typename SFINAE>
11283
    using json_serializer = JSONSerializer<T, SFINAE>;
11284
    /// helper type for initializer lists of basic_json values
11285
    using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
11286
11287
    using input_format_t = detail::input_format_t;
11288
    /// SAX interface type, see @ref nlohmann::json_sax
11289
    using json_sax_t = json_sax<basic_json>;
11290
11291
    ////////////////
11292
    // exceptions //
11293
    ////////////////
11294
11295
    /// @name exceptions
11296
    /// Classes to implement user-defined exceptions.
11297
    /// @{
11298
11299
    /// @copydoc detail::exception
11300
    using exception = detail::exception;
11301
    /// @copydoc detail::parse_error
11302
    using parse_error = detail::parse_error;
11303
    /// @copydoc detail::invalid_iterator
11304
    using invalid_iterator = detail::invalid_iterator;
11305
    /// @copydoc detail::type_error
11306
    using type_error = detail::type_error;
11307
    /// @copydoc detail::out_of_range
11308
    using out_of_range = detail::out_of_range;
11309
    /// @copydoc detail::other_error
11310
    using other_error = detail::other_error;
11311
11312
    /// @}
11313
11314
11315
    /////////////////////
11316
    // container types //
11317
    /////////////////////
11318
11319
    /// @name container types
11320
    /// The canonic container types to use @ref basic_json like any other STL
11321
    /// container.
11322
    /// @{
11323
11324
    /// the type of elements in a basic_json container
11325
    using value_type = basic_json;
11326
11327
    /// the type of an element reference
11328
    using reference = value_type&;
11329
    /// the type of an element const reference
11330
    using const_reference = const value_type&;
11331
11332
    /// a type to represent differences between iterators
11333
    using difference_type = std::ptrdiff_t;
11334
    /// a type to represent container sizes
11335
    using size_type = std::size_t;
11336
11337
    /// the allocator type
11338
    using allocator_type = AllocatorType<basic_json>;
11339
11340
    /// the type of an element pointer
11341
    using pointer = typename std::allocator_traits<allocator_type>::pointer;
11342
    /// the type of an element const pointer
11343
    using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
11344
11345
    /// an iterator for a basic_json container
11346
    using iterator = iter_impl<basic_json>;
11347
    /// a const iterator for a basic_json container
11348
    using const_iterator = iter_impl<const basic_json>;
11349
    /// a reverse iterator for a basic_json container
11350
    using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
11351
    /// a const reverse iterator for a basic_json container
11352
    using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
11353
11354
    /// @}
11355
11356
11357
    /*!
11358
    @brief returns the allocator associated with the container
11359
    */
11360
    static allocator_type get_allocator()
11361
    {
11362
        return allocator_type();
11363
    }
11364
11365
    /*!
11366
    @brief returns version information on the library
11367
11368
    This function returns a JSON object with information about the library,
11369
    including the version number and information on the platform and compiler.
11370
11371
    @return JSON object holding version information
11372
    key         | description
11373
    ----------- | ---------------
11374
    `compiler`  | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version).
11375
    `copyright` | The copyright line for the library as string.
11376
    `name`      | The name of the library as string.
11377
    `platform`  | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`.
11378
    `url`       | The URL of the project as string.
11379
    `version`   | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string).
11380
11381
    @liveexample{The following code shows an example output of the `meta()`
11382
    function.,meta}
11383
11384
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
11385
    changes to any JSON value.
11386
11387
    @complexity Constant.
11388
11389
    @since 2.1.0
11390
    */
11391
    static basic_json meta()
11392
    {
11393
        basic_json result;
11394
11395
        result["copyright"] = "(C) 2013-2017 Niels Lohmann";
11396
        result["name"] = "JSON for Modern C++";
11397
        result["url"] = "https://github.com/nlohmann/json";
11398
        result["version"]["string"] =
11399
            std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + "." +
11400
            std::to_string(NLOHMANN_JSON_VERSION_MINOR) + "." +
11401
            std::to_string(NLOHMANN_JSON_VERSION_PATCH);
11402
        result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR;
11403
        result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR;
11404
        result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH;
11405
11406
#ifdef _WIN32
11407
        result["platform"] = "win32";
11408
#elif defined __linux__
11409
        result["platform"] = "linux";
11410
#elif defined __APPLE__
11411
        result["platform"] = "apple";
11412
#elif defined __unix__
11413
        result["platform"] = "unix";
11414
#else
11415
        result["platform"] = "unknown";
11416
#endif
11417
11418
#if defined(__ICC) || defined(__INTEL_COMPILER)
11419
        result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
11420
#elif defined(__clang__)
11421
        result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
11422
#elif defined(__GNUC__) || defined(__GNUG__)
11423
        result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}};
11424
#elif defined(__HP_cc) || defined(__HP_aCC)
11425
        result["compiler"] = "hp"
11426
#elif defined(__IBMCPP__)
11427
        result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}};
11428
#elif defined(_MSC_VER)
11429
        result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}};
11430
#elif defined(__PGI)
11431
        result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}};
11432
#elif defined(__SUNPRO_CC)
11433
        result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}};
11434
#else
11435
        result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
11436
#endif
11437
11438
#ifdef __cplusplus
11439
        result["compiler"]["c++"] = std::to_string(__cplusplus);
11440
#else
11441
        result["compiler"]["c++"] = "unknown";
11442
#endif
11443
        return result;
11444
    }
11445
11446
11447
    ///////////////////////////
11448
    // JSON value data types //
11449
    ///////////////////////////
11450
11451
    /// @name JSON value data types
11452
    /// The data types to store a JSON value. These types are derived from
11453
    /// the template arguments passed to class @ref basic_json.
11454
    /// @{
11455
11456
#if defined(JSON_HAS_CPP_14)
11457
    // Use transparent comparator if possible, combined with perfect forwarding
11458
    // on find() and count() calls prevents unnecessary string construction.
11459
    using object_comparator_t = std::less<>;
11460
#else
11461
    using object_comparator_t = std::less<StringType>;
11462
#endif
11463
11464
    /*!
11465
    @brief a type for an object
11466
11467
    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows:
11468
    > An object is an unordered collection of zero or more name/value pairs,
11469
    > where a name is a string and a value is a string, number, boolean, null,
11470
    > object, or array.
11471
11472
    To store objects in C++, a type is defined by the template parameters
11473
    described below.
11474
11475
    @tparam ObjectType  the container to store objects (e.g., `std::map` or
11476
    `std::unordered_map`)
11477
    @tparam StringType the type of the keys or names (e.g., `std::string`).
11478
    The comparison function `std::less<StringType>` is used to order elements
11479
    inside the container.
11480
    @tparam AllocatorType the allocator to use for objects (e.g.,
11481
    `std::allocator`)
11482
11483
    #### Default type
11484
11485
    With the default values for @a ObjectType (`std::map`), @a StringType
11486
    (`std::string`), and @a AllocatorType (`std::allocator`), the default
11487
    value for @a object_t is:
11488
11489
    @code {.cpp}
11490
    std::map<
11491
      std::string, // key_type
11492
      basic_json, // value_type
11493
      std::less<std::string>, // key_compare
11494
      std::allocator<std::pair<const std::string, basic_json>> // allocator_type
11495
    >
11496
    @endcode
11497
11498
    #### Behavior
11499
11500
    The choice of @a object_t influences the behavior of the JSON class. With
11501
    the default type, objects have the following behavior:
11502
11503
    - When all names are unique, objects will be interoperable in the sense
11504
      that all software implementations receiving that object will agree on
11505
      the name-value mappings.
11506
    - When the names within an object are not unique, it is unspecified which
11507
      one of the values for a given key will be chosen. For instance,
11508
      `{"key": 2, "key": 1}` could be equal to either `{"key": 1}` or
11509
      `{"key": 2}`.
11510
    - Internally, name/value pairs are stored in lexicographical order of the
11511
      names. Objects will also be serialized (see @ref dump) in this order.
11512
      For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored
11513
      and serialized as `{"a": 2, "b": 1}`.
11514
    - When comparing objects, the order of the name/value pairs is irrelevant.
11515
      This makes objects interoperable in the sense that they will not be
11516
      affected by these differences. For instance, `{"b": 1, "a": 2}` and
11517
      `{"a": 2, "b": 1}` will be treated as equal.
11518
11519
    #### Limits
11520
11521
    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
11522
    > An implementation may set limits on the maximum depth of nesting.
11523
11524
    In this class, the object's limit of nesting is not explicitly constrained.
11525
    However, a maximum depth of nesting may be introduced by the compiler or
11526
    runtime environment. A theoretical limit can be queried by calling the
11527
    @ref max_size function of a JSON object.
11528
11529
    #### Storage
11530
11531
    Objects are stored as pointers in a @ref basic_json type. That is, for any
11532
    access to object values, a pointer of type `object_t*` must be
11533
    dereferenced.
11534
11535
    @sa @ref array_t -- type for an array value
11536
11537
    @since version 1.0.0
11538
11539
    @note The order name/value pairs are added to the object is *not*
11540
    preserved by the library. Therefore, iterating an object may return
11541
    name/value pairs in a different order than they were originally stored. In
11542
    fact, keys will be traversed in alphabetical order as `std::map` with
11543
    `std::less` is used by default. Please note this behavior conforms to [RFC
11544
    7159](http://rfc7159.net/rfc7159), because any order implements the
11545
    specified "unordered" nature of JSON objects.
11546
    */
11547
    using object_t = ObjectType<StringType,
11548
          basic_json,
11549
          object_comparator_t,
11550
          AllocatorType<std::pair<const StringType,
11551
          basic_json>>>;
11552
11553
    /*!
11554
    @brief a type for an array
11555
11556
    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:
11557
    > An array is an ordered sequence of zero or more values.
11558
11559
    To store objects in C++, a type is defined by the template parameters
11560
    explained below.
11561
11562
    @tparam ArrayType  container type to store arrays (e.g., `std::vector` or
11563
    `std::list`)
11564
    @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`)
11565
11566
    #### Default type
11567
11568
    With the default values for @a ArrayType (`std::vector`) and @a
11569
    AllocatorType (`std::allocator`), the default value for @a array_t is:
11570
11571
    @code {.cpp}
11572
    std::vector<
11573
      basic_json, // value_type
11574
      std::allocator<basic_json> // allocator_type
11575
    >
11576
    @endcode
11577
11578
    #### Limits
11579
11580
    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
11581
    > An implementation may set limits on the maximum depth of nesting.
11582
11583
    In this class, the array's limit of nesting is not explicitly constrained.
11584
    However, a maximum depth of nesting may be introduced by the compiler or
11585
    runtime environment. A theoretical limit can be queried by calling the
11586
    @ref max_size function of a JSON array.
11587
11588
    #### Storage
11589
11590
    Arrays are stored as pointers in a @ref basic_json type. That is, for any
11591
    access to array values, a pointer of type `array_t*` must be dereferenced.
11592
11593
    @sa @ref object_t -- type for an object value
11594
11595
    @since version 1.0.0
11596
    */
11597
    using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
11598
11599
    /*!
11600
    @brief a type for a string
11601
11602
    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows:
11603
    > A string is a sequence of zero or more Unicode characters.
11604
11605
    To store objects in C++, a type is defined by the template parameter
11606
    described below. Unicode values are split by the JSON class into
11607
    byte-sized characters during deserialization.
11608
11609
    @tparam StringType  the container to store strings (e.g., `std::string`).
11610
    Note this container is used for keys/names in objects, see @ref object_t.
11611
11612
    #### Default type
11613
11614
    With the default values for @a StringType (`std::string`), the default
11615
    value for @a string_t is:
11616
11617
    @code {.cpp}
11618
    std::string
11619
    @endcode
11620
11621
    #### Encoding
11622
11623
    Strings are stored in UTF-8 encoding. Therefore, functions like
11624
    `std::string::size()` or `std::string::length()` return the number of
11625
    bytes in the string rather than the number of characters or glyphs.
11626
11627
    #### String comparison
11628
11629
    [RFC 7159](http://rfc7159.net/rfc7159) states:
11630
    > Software implementations are typically required to test names of object
11631
    > members for equality. Implementations that transform the textual
11632
    > representation into sequences of Unicode code units and then perform the
11633
    > comparison numerically, code unit by code unit, are interoperable in the
11634
    > sense that implementations will agree in all cases on equality or
11635
    > inequality of two strings. For example, implementations that compare
11636
    > strings with escaped characters unconverted may incorrectly find that
11637
    > `"a\\b"` and `"a\u005Cb"` are not equal.
11638
11639
    This implementation is interoperable as it does compare strings code unit
11640
    by code unit.
11641
11642
    #### Storage
11643
11644
    String values are stored as pointers in a @ref basic_json type. That is,
11645
    for any access to string values, a pointer of type `string_t*` must be
11646
    dereferenced.
11647
11648
    @since version 1.0.0
11649
    */
11650
    using string_t = StringType;
11651
11652
    /*!
11653
    @brief a type for a boolean
11654
11655
    [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a
11656
    type which differentiates the two literals `true` and `false`.
11657
11658
    To store objects in C++, a type is defined by the template parameter @a
11659
    BooleanType which chooses the type to use.
11660
11661
    #### Default type
11662
11663
    With the default values for @a BooleanType (`bool`), the default value for
11664
    @a boolean_t is:
11665
11666
    @code {.cpp}
11667
    bool
11668
    @endcode
11669
11670
    #### Storage
11671
11672
    Boolean values are stored directly inside a @ref basic_json type.
11673
11674
    @since version 1.0.0
11675
    */
11676
    using boolean_t = BooleanType;
11677
11678
    /*!
11679
    @brief a type for a number (integer)
11680
11681
    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
11682
    > The representation of numbers is similar to that used in most
11683
    > programming languages. A number is represented in base 10 using decimal
11684
    > digits. It contains an integer component that may be prefixed with an
11685
    > optional minus sign, which may be followed by a fraction part and/or an
11686
    > exponent part. Leading zeros are not allowed. (...) Numeric values that
11687
    > cannot be represented in the grammar below (such as Infinity and NaN)
11688
    > are not permitted.
11689
11690
    This description includes both integer and floating-point numbers.
11691
    However, C++ allows more precise storage if it is known whether the number
11692
    is a signed integer, an unsigned integer or a floating-point number.
11693
    Therefore, three different types, @ref number_integer_t, @ref
11694
    number_unsigned_t and @ref number_float_t are used.
11695
11696
    To store integer numbers in C++, a type is defined by the template
11697
    parameter @a NumberIntegerType which chooses the type to use.
11698
11699
    #### Default type
11700
11701
    With the default values for @a NumberIntegerType (`int64_t`), the default
11702
    value for @a number_integer_t is:
11703
11704
    @code {.cpp}
11705
    int64_t
11706
    @endcode
11707
11708
    #### Default behavior
11709
11710
    - The restrictions about leading zeros is not enforced in C++. Instead,
11711
      leading zeros in integer literals lead to an interpretation as octal
11712
      number. Internally, the value will be stored as decimal number. For
11713
      instance, the C++ integer literal `010` will be serialized to `8`.
11714
      During deserialization, leading zeros yield an error.
11715
    - Not-a-number (NaN) values will be serialized to `null`.
11716
11717
    #### Limits
11718
11719
    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
11720
    > An implementation may set limits on the range and precision of numbers.
11721
11722
    When the default type is used, the maximal integer number that can be
11723
    stored is `9223372036854775807` (INT64_MAX) and the minimal integer number
11724
    that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers
11725
    that are out of range will yield over/underflow when used in a
11726
    constructor. During deserialization, too large or small integer numbers
11727
    will be automatically be stored as @ref number_unsigned_t or @ref
11728
    number_float_t.
11729
11730
    [RFC 7159](http://rfc7159.net/rfc7159) further states:
11731
    > Note that when such software is used, numbers that are integers and are
11732
    > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
11733
    > that implementations will agree exactly on their numeric values.
11734
11735
    As this range is a subrange of the exactly supported range [INT64_MIN,
11736
    INT64_MAX], this class's integer type is interoperable.
11737
11738
    #### Storage
11739
11740
    Integer number values are stored directly inside a @ref basic_json type.
11741
11742
    @sa @ref number_float_t -- type for number values (floating-point)
11743
11744
    @sa @ref number_unsigned_t -- type for number values (unsigned integer)
11745
11746
    @since version 1.0.0
11747
    */
11748
    using number_integer_t = NumberIntegerType;
11749
11750
    /*!
11751
    @brief a type for a number (unsigned)
11752
11753
    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
11754
    > The representation of numbers is similar to that used in most
11755
    > programming languages. A number is represented in base 10 using decimal
11756
    > digits. It contains an integer component that may be prefixed with an
11757
    > optional minus sign, which may be followed by a fraction part and/or an
11758
    > exponent part. Leading zeros are not allowed. (...) Numeric values that
11759
    > cannot be represented in the grammar below (such as Infinity and NaN)
11760
    > are not permitted.
11761
11762
    This description includes both integer and floating-point numbers.
11763
    However, C++ allows more precise storage if it is known whether the number
11764
    is a signed integer, an unsigned integer or a floating-point number.
11765
    Therefore, three different types, @ref number_integer_t, @ref
11766
    number_unsigned_t and @ref number_float_t are used.
11767
11768
    To store unsigned integer numbers in C++, a type is defined by the
11769
    template parameter @a NumberUnsignedType which chooses the type to use.
11770
11771
    #### Default type
11772
11773
    With the default values for @a NumberUnsignedType (`uint64_t`), the
11774
    default value for @a number_unsigned_t is:
11775
11776
    @code {.cpp}
11777
    uint64_t
11778
    @endcode
11779
11780
    #### Default behavior
11781
11782
    - The restrictions about leading zeros is not enforced in C++. Instead,
11783
      leading zeros in integer literals lead to an interpretation as octal
11784
      number. Internally, the value will be stored as decimal number. For
11785
      instance, the C++ integer literal `010` will be serialized to `8`.
11786
      During deserialization, leading zeros yield an error.
11787
    - Not-a-number (NaN) values will be serialized to `null`.
11788
11789
    #### Limits
11790
11791
    [RFC 7159](http://rfc7159.net/rfc7159) specifies:
11792
    > An implementation may set limits on the range and precision of numbers.
11793
11794
    When the default type is used, the maximal integer number that can be
11795
    stored is `18446744073709551615` (UINT64_MAX) and the minimal integer
11796
    number that can be stored is `0`. Integer numbers that are out of range
11797
    will yield over/underflow when used in a constructor. During
11798
    deserialization, too large or small integer numbers will be automatically
11799
    be stored as @ref number_integer_t or @ref number_float_t.
11800
11801
    [RFC 7159](http://rfc7159.net/rfc7159) further states:
11802
    > Note that when such software is used, numbers that are integers and are
11803
    > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
11804
    > that implementations will agree exactly on their numeric values.
11805
11806
    As this range is a subrange (when considered in conjunction with the
11807
    number_integer_t type) of the exactly supported range [0, UINT64_MAX],
11808
    this class's integer type is interoperable.
11809
11810
    #### Storage
11811
11812
    Integer number values are stored directly inside a @ref basic_json type.
11813
11814
    @sa @ref number_float_t -- type for number values (floating-point)
11815
    @sa @ref number_integer_t -- type for number values (integer)
11816
11817
    @since version 2.0.0
11818
    */
11819
    using number_unsigned_t = NumberUnsignedType;
11820
11821
    /*!
11822
    @brief a type for a number (floating-point)
11823
11824
    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
11825
    > The representation of numbers is similar to that used in most
11826
    > programming languages. A number is represented in base 10 using decimal
11827
    > digits. It contains an integer component that may be prefixed with an
11828
    > optional minus sign, which may be followed by a fraction part and/or an
11829
    > exponent part. Leading zeros are not allowed. (...) Numeric values that
11830
    > cannot be represented in the grammar below (such as Infinity and NaN)
11831
    > are not permitted.
11832
11833
    This description includes both integer and floating-point numbers.
11834
    However, C++ allows more precise storage if it is known whether the number
11835
    is a signed integer, an unsigned integer or a floating-point number.
11836
    Therefore, three different types, @ref number_integer_t, @ref
11837
    number_unsigned_t and @ref number_float_t are used.
11838
11839
    To store floating-point numbers in C++, a type is defined by the template
11840
    parameter @a NumberFloatType which chooses the type to use.
11841
11842
    #### Default type
11843
11844
    With the default values for @a NumberFloatType (`double`), the default
11845
    value for @a number_float_t is:
11846
11847
    @code {.cpp}
11848
    double
11849
    @endcode
11850
11851
    #### Default behavior
11852
11853
    - The restrictions about leading zeros is not enforced in C++. Instead,
11854
      leading zeros in floating-point literals will be ignored. Internally,
11855
      the value will be stored as decimal number. For instance, the C++
11856
      floating-point literal `01.2` will be serialized to `1.2`. During
11857
      deserialization, leading zeros yield an error.
11858
    - Not-a-number (NaN) values will be serialized to `null`.
11859
11860
    #### Limits
11861
11862
    [RFC 7159](http://rfc7159.net/rfc7159) states:
11863
    > This specification allows implementations to set limits on the range and
11864
    > precision of numbers accepted. Since software that implements IEEE
11865
    > 754-2008 binary64 (double precision) numbers is generally available and
11866
    > widely used, good interoperability can be achieved by implementations
11867
    > that expect no more precision or range than these provide, in the sense
11868
    > that implementations will approximate JSON numbers within the expected
11869
    > precision.
11870
11871
    This implementation does exactly follow this approach, as it uses double
11872
    precision floating-point numbers. Note values smaller than
11873
    `-1.79769313486232e+308` and values greater than `1.79769313486232e+308`
11874
    will be stored as NaN internally and be serialized to `null`.
11875
11876
    #### Storage
11877
11878
    Floating-point number values are stored directly inside a @ref basic_json
11879
    type.
11880
11881
    @sa @ref number_integer_t -- type for number values (integer)
11882
11883
    @sa @ref number_unsigned_t -- type for number values (unsigned integer)
11884
11885
    @since version 1.0.0
11886
    */
11887
    using number_float_t = NumberFloatType;
11888
11889
    /// @}
11890
11891
  private:
11892
11893
    /// helper for exception-safe object creation
11894
    template<typename T, typename... Args>
11895
    static T* create(Args&& ... args)
11896
616k
    {
11897
616k
        AllocatorType<T> alloc;
11898
616k
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
11899
616k
11900
616k
        auto deleter = [&](T * object)
11901
616k
        {
11902
0
            AllocatorTraits::deallocate(alloc, object, 1);
11903
0
        };
Unexecuted instantiation: _ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS1_IS8_SA_St4lessIvESaISt4pairIKS8_SA_EEEJEEEPT_DpOT0_ENKUlPSI_E_clESO_
Unexecuted instantiation: _ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS2_ISA_SaISA_EEJEEEPT_DpOT0_ENKUlPSD_E_clESJ_
Unexecuted instantiation: _ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRA1_KcEEEPT_DpOT0_ENKUlPS8_E_clESK_
Unexecuted instantiation: _ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS1_IS8_SA_St4lessIvESaISt4pairIKS8_SA_EEEJRKSI_EEEPT_DpOT0_ENKUlPSI_E_clESQ_
Unexecuted instantiation: _ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS2_ISA_SaISA_EEJRKSD_EEEPT_DpOT0_ENKUlPSD_E_clESL_
Unexecuted instantiation: _ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRKS8_EEEPT_DpOT0_ENKUlPS8_E_clESJ_
Unexecuted instantiation: _ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRA474_KcEEEPT_DpOT0_ENKUlPS8_E_clESK_
Unexecuted instantiation: _ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JS8_EEEPT_DpOT0_ENKUlPS8_E_clESH_
Unexecuted instantiation: _ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRKPKcEEEPT_DpOT0_ENKUlPS8_E_clESL_
Unexecuted instantiation: _ZZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRA6_KcEEEPT_DpOT0_ENKUlPS8_E_clESK_
11904
616k
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
11905
616k
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
11906
616k
        assert(object != nullptr);
11907
616k
        return object.release();
11908
616k
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS1_IS8_SA_St4lessIvESaISt4pairIKS8_SA_EEEJEEEPT_DpOT0_
Line
Count
Source
11896
209k
    {
11897
209k
        AllocatorType<T> alloc;
11898
209k
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
11899
209k
11900
209k
        auto deleter = [&](T * object)
11901
209k
        {
11902
209k
            AllocatorTraits::deallocate(alloc, object, 1);
11903
209k
        };
11904
209k
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
11905
209k
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
11906
209k
        assert(object != nullptr);
11907
209k
        return object.release();
11908
209k
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS2_ISA_SaISA_EEJEEEPT_DpOT0_
Line
Count
Source
11896
2.45k
    {
11897
2.45k
        AllocatorType<T> alloc;
11898
2.45k
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
11899
2.45k
11900
2.45k
        auto deleter = [&](T * object)
11901
2.45k
        {
11902
2.45k
            AllocatorTraits::deallocate(alloc, object, 1);
11903
2.45k
        };
11904
2.45k
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
11905
2.45k
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
11906
2.45k
        assert(object != nullptr);
11907
2.45k
        return object.release();
11908
2.45k
    }
Unexecuted instantiation: _ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRA1_KcEEEPT_DpOT0_
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS1_IS8_SA_St4lessIvESaISt4pairIKS8_SA_EEEJRKSI_EEEPT_DpOT0_
Line
Count
Source
11896
23.4k
    {
11897
23.4k
        AllocatorType<T> alloc;
11898
23.4k
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
11899
23.4k
11900
23.4k
        auto deleter = [&](T * object)
11901
23.4k
        {
11902
23.4k
            AllocatorTraits::deallocate(alloc, object, 1);
11903
23.4k
        };
11904
23.4k
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
11905
23.4k
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
11906
23.4k
        assert(object != nullptr);
11907
23.4k
        return object.release();
11908
23.4k
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS2_ISA_SaISA_EEJRKSD_EEEPT_DpOT0_
Line
Count
Source
11896
96
    {
11897
96
        AllocatorType<T> alloc;
11898
96
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
11899
96
11900
96
        auto deleter = [&](T * object)
11901
96
        {
11902
96
            AllocatorTraits::deallocate(alloc, object, 1);
11903
96
        };
11904
96
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
11905
96
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
11906
96
        assert(object != nullptr);
11907
96
        return object.release();
11908
96
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRKS8_EEEPT_DpOT0_
Line
Count
Source
11896
378k
    {
11897
378k
        AllocatorType<T> alloc;
11898
378k
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
11899
378k
11900
378k
        auto deleter = [&](T * object)
11901
378k
        {
11902
378k
            AllocatorTraits::deallocate(alloc, object, 1);
11903
378k
        };
11904
378k
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
11905
378k
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
11906
378k
        assert(object != nullptr);
11907
378k
        return object.release();
11908
378k
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRA474_KcEEEPT_DpOT0_
Line
Count
Source
11896
812
    {
11897
812
        AllocatorType<T> alloc;
11898
812
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
11899
812
11900
812
        auto deleter = [&](T * object)
11901
812
        {
11902
812
            AllocatorTraits::deallocate(alloc, object, 1);
11903
812
        };
11904
812
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
11905
812
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
11906
812
        assert(object != nullptr);
11907
812
        return object.release();
11908
812
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JS8_EEEPT_DpOT0_
Line
Count
Source
11896
1.76k
    {
11897
1.76k
        AllocatorType<T> alloc;
11898
1.76k
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
11899
1.76k
11900
1.76k
        auto deleter = [&](T * object)
11901
1.76k
        {
11902
1.76k
            AllocatorTraits::deallocate(alloc, object, 1);
11903
1.76k
        };
11904
1.76k
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
11905
1.76k
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
11906
1.76k
        assert(object != nullptr);
11907
1.76k
        return object.release();
11908
1.76k
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRKPKcEEEPT_DpOT0_
Line
Count
Source
11896
40
    {
11897
40
        AllocatorType<T> alloc;
11898
40
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
11899
40
11900
40
        auto deleter = [&](T * object)
11901
40
        {
11902
40
            AllocatorTraits::deallocate(alloc, object, 1);
11903
40
        };
11904
40
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
11905
40
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
11906
40
        assert(object != nullptr);
11907
40
        return object.release();
11908
40
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE6createIS8_JRA6_KcEEEPT_DpOT0_
Line
Count
Source
11896
4
    {
11897
4
        AllocatorType<T> alloc;
11898
4
        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
11899
4
11900
4
        auto deleter = [&](T * object)
11901
4
        {
11902
4
            AllocatorTraits::deallocate(alloc, object, 1);
11903
4
        };
11904
4
        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
11905
4
        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
11906
4
        assert(object != nullptr);
11907
4
        return object.release();
11908
4
    }
11909
11910
    ////////////////////////
11911
    // JSON value storage //
11912
    ////////////////////////
11913
11914
    /*!
11915
    @brief a JSON value
11916
11917
    The actual storage for a JSON value of the @ref basic_json class. This
11918
    union combines the different storage types for the JSON value types
11919
    defined in @ref value_t.
11920
11921
    JSON type | value_t type    | used type
11922
    --------- | --------------- | ------------------------
11923
    object    | object          | pointer to @ref object_t
11924
    array     | array           | pointer to @ref array_t
11925
    string    | string          | pointer to @ref string_t
11926
    boolean   | boolean         | @ref boolean_t
11927
    number    | number_integer  | @ref number_integer_t
11928
    number    | number_unsigned | @ref number_unsigned_t
11929
    number    | number_float    | @ref number_float_t
11930
    null      | null            | *no value is stored*
11931
11932
    @note Variable-length types (objects, arrays, and strings) are stored as
11933
    pointers. The size of the union should not exceed 64 bits if the default
11934
    value types are used.
11935
11936
    @since version 1.0.0
11937
    */
11938
    union json_value
11939
    {
11940
        /// object (stored with pointer to save storage)
11941
        object_t* object;
11942
        /// array (stored with pointer to save storage)
11943
        array_t* array;
11944
        /// string (stored with pointer to save storage)
11945
        string_t* string;
11946
        /// boolean
11947
        boolean_t boolean;
11948
        /// number (integer)
11949
        number_integer_t number_integer;
11950
        /// number (unsigned integer)
11951
        number_unsigned_t number_unsigned;
11952
        /// number (floating-point)
11953
        number_float_t number_float;
11954
11955
        /// default constructor (for null values)
11956
        json_value() = default;
11957
        /// constructor for booleans
11958
2.50k
        json_value(boolean_t v) noexcept : boolean(v) {}
11959
        /// constructor for numbers (integer)
11960
39.1k
        json_value(number_integer_t v) noexcept : number_integer(v) {}
11961
        /// constructor for numbers (unsigned)
11962
329k
        json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
11963
        /// constructor for numbers (floating-point)
11964
245k
        json_value(number_float_t v) noexcept : number_float(v) {}
11965
        /// constructor for empty values of a given type
11966
        json_value(value_t t)
11967
1.23M
        {
11968
1.23M
            switch (t)
11969
1.23M
            {
11970
1.23M
                case value_t::object:
11971
208k
                {
11972
208k
                    object = create<object_t>();
11973
208k
                    break;
11974
1.23M
                }
11975
1.23M
11976
1.23M
                case value_t::array:
11977
2.45k
                {
11978
2.45k
                    array = create<array_t>();
11979
2.45k
                    break;
11980
1.23M
                }
11981
1.23M
11982
1.23M
                case value_t::string:
11983
0
                {
11984
0
                    string = create<string_t>("");
11985
0
                    break;
11986
1.23M
                }
11987
1.23M
11988
1.23M
                case value_t::boolean:
11989
0
                {
11990
0
                    boolean = boolean_t(false);
11991
0
                    break;
11992
1.23M
                }
11993
1.23M
11994
1.23M
                case value_t::number_integer:
11995
0
                {
11996
0
                    number_integer = number_integer_t(0);
11997
0
                    break;
11998
1.23M
                }
11999
1.23M
12000
1.23M
                case value_t::number_unsigned:
12001
0
                {
12002
0
                    number_unsigned = number_unsigned_t(0);
12003
0
                    break;
12004
1.23M
                }
12005
1.23M
12006
1.23M
                case value_t::number_float:
12007
0
                {
12008
0
                    number_float = number_float_t(0.0);
12009
0
                    break;
12010
1.23M
                }
12011
1.23M
12012
1.23M
                case value_t::null:
12013
1.02M
                {
12014
1.02M
                    object = nullptr;  // silence warning, see #821
12015
1.02M
                    break;
12016
1.23M
                }
12017
1.23M
12018
1.23M
                default:
12019
0
                {
12020
0
                    object = nullptr;  // silence warning, see #821
12021
0
                    if (JSON_UNLIKELY(t == value_t::null))
12022
0
                    {
12023
0
                        JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.2.0")); // LCOV_EXCL_LINE
12024
0
                    }
12025
0
                    break;
12026
0
                }
12027
1.23M
            }
12028
1.23M
        }
12029
12030
        /// constructor for strings
12031
        json_value(const string_t& value)
12032
378k
        {
12033
378k
            string = create<string_t>(value);
12034
378k
        }
12035
12036
        /// constructor for rvalue strings
12037
        json_value(string_t&& value)
12038
1.76k
        {
12039
1.76k
            string = create<string_t>(std::move(value));
12040
1.76k
        }
12041
12042
        /// constructor for objects
12043
        json_value(const object_t& value)
12044
23.4k
        {
12045
23.4k
            object = create<object_t>(value);
12046
23.4k
        }
12047
12048
        /// constructor for rvalue objects
12049
        json_value(object_t&& value)
12050
        {
12051
            object = create<object_t>(std::move(value));
12052
        }
12053
12054
        /// constructor for arrays
12055
        json_value(const array_t& value)
12056
96
        {
12057
96
            array = create<array_t>(value);
12058
96
        }
12059
12060
        /// constructor for rvalue arrays
12061
        json_value(array_t&& value)
12062
        {
12063
            array = create<array_t>(std::move(value));
12064
        }
12065
12066
        void destroy(value_t t) noexcept
12067
2.30M
        {
12068
2.30M
            switch (t)
12069
2.30M
            {
12070
2.30M
                case value_t::object:
12071
232k
                {
12072
232k
                    AllocatorType<object_t> alloc;
12073
232k
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
12074
232k
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
12075
232k
                    break;
12076
2.30M
                }
12077
2.30M
12078
2.30M
                case value_t::array:
12079
2.54k
                {
12080
2.54k
                    AllocatorType<array_t> alloc;
12081
2.54k
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
12082
2.54k
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
12083
2.54k
                    break;
12084
2.30M
                }
12085
2.30M
12086
2.30M
                case value_t::string:
12087
381k
                {
12088
381k
                    AllocatorType<string_t> alloc;
12089
381k
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
12090
381k
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
12091
381k
                    break;
12092
2.30M
                }
12093
2.30M
12094
2.30M
                default:
12095
1.68M
                {
12096
1.68M
                    break;
12097
2.30M
                }
12098
2.30M
            }
12099
2.30M
        }
12100
    };
12101
12102
    /*!
12103
    @brief checks the class invariants
12104
12105
    This function asserts the class invariants. It needs to be called at the
12106
    end of every constructor to make sure that created objects respect the
12107
    invariant. Furthermore, it has to be called each time the type of a JSON
12108
    value is changed, because the invariant expresses a relationship between
12109
    @a m_type and @a m_value.
12110
    */
12111
    void assert_invariant() const noexcept
12112
8.75M
    {
12113
8.75M
        assert(m_type != value_t::object or m_value.object != nullptr);
12114
8.75M
        assert(m_type != value_t::array or m_value.array != nullptr);
12115
8.75M
        assert(m_type != value_t::string or m_value.string != nullptr);
12116
8.75M
    }
12117
12118
  public:
12119
    //////////////////////////
12120
    // JSON parser callback //
12121
    //////////////////////////
12122
12123
    /*!
12124
    @brief parser event types
12125
12126
    The parser callback distinguishes the following events:
12127
    - `object_start`: the parser read `{` and started to process a JSON object
12128
    - `key`: the parser read a key of a value in an object
12129
    - `object_end`: the parser read `}` and finished processing a JSON object
12130
    - `array_start`: the parser read `[` and started to process a JSON array
12131
    - `array_end`: the parser read `]` and finished processing a JSON array
12132
    - `value`: the parser finished reading a JSON value
12133
12134
    @image html callback_events.png "Example when certain parse events are triggered"
12135
12136
    @sa @ref parser_callback_t for more information and examples
12137
    */
12138
    using parse_event_t = typename parser::parse_event_t;
12139
12140
    /*!
12141
    @brief per-element parser callback type
12142
12143
    With a parser callback function, the result of parsing a JSON text can be
12144
    influenced. When passed to @ref parse, it is called on certain events
12145
    (passed as @ref parse_event_t via parameter @a event) with a set recursion
12146
    depth @a depth and context JSON value @a parsed. The return value of the
12147
    callback function is a boolean indicating whether the element that emitted
12148
    the callback shall be kept or not.
12149
12150
    We distinguish six scenarios (determined by the event type) in which the
12151
    callback function can be called. The following table describes the values
12152
    of the parameters @a depth, @a event, and @a parsed.
12153
12154
    parameter @a event | description | parameter @a depth | parameter @a parsed
12155
    ------------------ | ----------- | ------------------ | -------------------
12156
    parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded
12157
    parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key
12158
    parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object
12159
    parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded
12160
    parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array
12161
    parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value
12162
12163
    @image html callback_events.png "Example when certain parse events are triggered"
12164
12165
    Discarding a value (i.e., returning `false`) has different effects
12166
    depending on the context in which function was called:
12167
12168
    - Discarded values in structured types are skipped. That is, the parser
12169
      will behave as if the discarded value was never read.
12170
    - In case a value outside a structured type is skipped, it is replaced
12171
      with `null`. This case happens if the top-level element is skipped.
12172
12173
    @param[in] depth  the depth of the recursion during parsing
12174
12175
    @param[in] event  an event of type parse_event_t indicating the context in
12176
    the callback function has been called
12177
12178
    @param[in,out] parsed  the current intermediate parse result; note that
12179
    writing to this value has no effect for parse_event_t::key events
12180
12181
    @return Whether the JSON value which called the function during parsing
12182
    should be kept (`true`) or not (`false`). In the latter case, it is either
12183
    skipped completely or replaced by an empty discarded object.
12184
12185
    @sa @ref parse for examples
12186
12187
    @since version 1.0.0
12188
    */
12189
    using parser_callback_t = typename parser::parser_callback_t;
12190
12191
    //////////////////
12192
    // constructors //
12193
    //////////////////
12194
12195
    /// @name constructors and destructors
12196
    /// Constructors of class @ref basic_json, copy/move constructor, copy
12197
    /// assignment, static functions creating objects, and the destructor.
12198
    /// @{
12199
12200
    /*!
12201
    @brief create an empty value with a given type
12202
12203
    Create an empty JSON value with a given type. The value will be default
12204
    initialized with an empty value which depends on the type:
12205
12206
    Value type  | initial value
12207
    ----------- | -------------
12208
    null        | `null`
12209
    boolean     | `false`
12210
    string      | `""`
12211
    number      | `0`
12212
    object      | `{}`
12213
    array       | `[]`
12214
12215
    @param[in] v  the type of the value to create
12216
12217
    @complexity Constant.
12218
12219
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
12220
    changes to any JSON value.
12221
12222
    @liveexample{The following code shows the constructor for different @ref
12223
    value_t values,basic_json__value_t}
12224
12225
    @sa @ref clear() -- restores the postcondition of this constructor
12226
12227
    @since version 1.0.0
12228
    */
12229
    basic_json(const value_t v)
12230
        : m_type(v), m_value(v)
12231
1.23M
    {
12232
1.23M
        assert_invariant();
12233
1.23M
    }
12234
12235
    /*!
12236
    @brief create a null object
12237
12238
    Create a `null` JSON value. It either takes a null pointer as parameter
12239
    (explicitly creating `null`) or no parameter (implicitly creating `null`).
12240
    The passed null pointer itself is not read -- it is only used to choose
12241
    the right constructor.
12242
12243
    @complexity Constant.
12244
12245
    @exceptionsafety No-throw guarantee: this constructor never throws
12246
    exceptions.
12247
12248
    @liveexample{The following code shows the constructor with and without a
12249
    null pointer parameter.,basic_json__nullptr_t}
12250
12251
    @since version 1.0.0
12252
    */
12253
    basic_json(std::nullptr_t = nullptr) noexcept
12254
        : basic_json(value_t::null)
12255
1.02M
    {
12256
1.02M
        assert_invariant();
12257
1.02M
    }
12258
12259
    /*!
12260
    @brief create a JSON value
12261
12262
    This is a "catch all" constructor for all compatible JSON types; that is,
12263
    types for which a `to_json()` method exists. The constructor forwards the
12264
    parameter @a val to that method (to `json_serializer<U>::to_json` method
12265
    with `U = uncvref_t<CompatibleType>`, to be exact).
12266
12267
    Template type @a CompatibleType includes, but is not limited to, the
12268
    following types:
12269
    - **arrays**: @ref array_t and all kinds of compatible containers such as
12270
      `std::vector`, `std::deque`, `std::list`, `std::forward_list`,
12271
      `std::array`, `std::valarray`, `std::set`, `std::unordered_set`,
12272
      `std::multiset`, and `std::unordered_multiset` with a `value_type` from
12273
      which a @ref basic_json value can be constructed.
12274
    - **objects**: @ref object_t and all kinds of compatible associative
12275
      containers such as `std::map`, `std::unordered_map`, `std::multimap`,
12276
      and `std::unordered_multimap` with a `key_type` compatible to
12277
      @ref string_t and a `value_type` from which a @ref basic_json value can
12278
      be constructed.
12279
    - **strings**: @ref string_t, string literals, and all compatible string
12280
      containers can be used.
12281
    - **numbers**: @ref number_integer_t, @ref number_unsigned_t,
12282
      @ref number_float_t, and all convertible number types such as `int`,
12283
      `size_t`, `int64_t`, `float` or `double` can be used.
12284
    - **boolean**: @ref boolean_t / `bool` can be used.
12285
12286
    See the examples below.
12287
12288
    @tparam CompatibleType a type such that:
12289
    - @a CompatibleType is not derived from `std::istream`,
12290
    - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move
12291
         constructors),
12292
    - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments)
12293
    - @a CompatibleType is not a @ref basic_json nested type (e.g.,
12294
         @ref json_pointer, @ref iterator, etc ...)
12295
    - @ref @ref json_serializer<U> has a
12296
         `to_json(basic_json_t&, CompatibleType&&)` method
12297
12298
    @tparam U = `uncvref_t<CompatibleType>`
12299
12300
    @param[in] val the value to be forwarded to the respective constructor
12301
12302
    @complexity Usually linear in the size of the passed @a val, also
12303
                depending on the implementation of the called `to_json()`
12304
                method.
12305
12306
    @exceptionsafety Depends on the called constructor. For types directly
12307
    supported by the library (i.e., all types for which no `to_json()` function
12308
    was provided), strong guarantee holds: if an exception is thrown, there are
12309
    no changes to any JSON value.
12310
12311
    @liveexample{The following code shows the constructor with several
12312
    compatible types.,basic_json__CompatibleType}
12313
12314
    @since version 2.1.0
12315
    */
12316
    template <typename CompatibleType,
12317
              typename U = detail::uncvref_t<CompatibleType>,
12318
              detail::enable_if_t<
12319
                  not detail::is_basic_json<U>::value and detail::is_compatible_type<basic_json_t, U>::value, int> = 0>
12320
    basic_json(CompatibleType && val) noexcept(noexcept(
12321
                JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
12322
                                           std::forward<CompatibleType>(val))))
12323
847k
    {
12324
847k
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
12325
847k
        assert_invariant();
12326
847k
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRS8_S8_Li0EEEOT_
Line
Count
Source
12323
255k
    {
12324
255k
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
12325
255k
        assert_invariant();
12326
255k
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRddLi0EEEOT_
Line
Count
Source
12323
234k
    {
12324
234k
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
12325
234k
        assert_invariant();
12326
234k
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRbbLi0EEEOT_
Line
Count
Source
12323
2.45k
    {
12324
2.45k
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
12325
2.45k
        assert_invariant();
12326
2.45k
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRllLi0EEEOT_
Line
Count
Source
12323
37.4k
    {
12324
37.4k
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
12325
37.4k
        assert_invariant();
12326
37.4k
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRmmLi0EEEOT_
Line
Count
Source
12323
314k
    {
12324
314k
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
12325
314k
        assert_invariant();
12326
314k
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRA474_KcA474_cLi0EEEOT_
Line
Count
Source
12323
812
    {
12324
812
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
12325
812
        assert_invariant();
12326
812
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IS8_S8_Li0EEEOT_
Line
Count
Source
12323
1.76k
    {
12324
1.76k
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
12325
1.76k
        assert_invariant();
12326
1.76k
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IKS8_S8_Li0EEEOT_
Line
Count
Source
12323
196
    {
12324
196
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
12325
196
        assert_invariant();
12326
196
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRjjLi0EEEOT_
Line
Count
Source
12323
588
    {
12324
588
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
12325
588
        assert_invariant();
12326
588
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRKPKcSD_Li0EEEOT_
Line
Count
Source
12323
40
    {
12324
40
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
12325
40
        assert_invariant();
12326
40
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IbbLi0EEEOT_
Line
Count
Source
12323
4
    {
12324
4
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
12325
4
        assert_invariant();
12326
4
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IddLi0EEEOT_
Line
Count
Source
12323
4
    {
12324
4
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
12325
4
        assert_invariant();
12326
4
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IRA6_KcA6_cLi0EEEOT_
Line
Count
Source
12323
4
    {
12324
4
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
12325
4
        assert_invariant();
12326
4
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEEC2IiiLi0EEEOT_
Line
Count
Source
12323
4
    {
12324
4
        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
12325
4
        assert_invariant();
12326
4
    }
12327
12328
    /*!
12329
    @brief create a JSON value from an existing one
12330
12331
    This is a constructor for existing @ref basic_json types.
12332
    It does not hijack copy/move constructors, since the parameter has different
12333
    template arguments than the current ones.
12334
12335
    The constructor tries to convert the internal @ref m_value of the parameter.
12336
12337
    @tparam BasicJsonType a type such that:
12338
    - @a BasicJsonType is a @ref basic_json type.
12339
    - @a BasicJsonType has different template arguments than @ref basic_json_t.
12340
12341
    @param[in] val the @ref basic_json value to be converted.
12342
12343
    @complexity Usually linear in the size of the passed @a val, also
12344
                depending on the implementation of the called `to_json()`
12345
                method.
12346
12347
    @exceptionsafety Depends on the called constructor. For types directly
12348
    supported by the library (i.e., all types for which no `to_json()` function
12349
    was provided), strong guarantee holds: if an exception is thrown, there are
12350
    no changes to any JSON value.
12351
12352
    @since version 3.2.0
12353
    */
12354
    template <typename BasicJsonType,
12355
              detail::enable_if_t<
12356
                  detail::is_basic_json<BasicJsonType>::value and not std::is_same<basic_json, BasicJsonType>::value, int> = 0>
12357
    basic_json(const BasicJsonType& val)
12358
    {
12359
        using other_boolean_t = typename BasicJsonType::boolean_t;
12360
        using other_number_float_t = typename BasicJsonType::number_float_t;
12361
        using other_number_integer_t = typename BasicJsonType::number_integer_t;
12362
        using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
12363
        using other_string_t = typename BasicJsonType::string_t;
12364
        using other_object_t = typename BasicJsonType::object_t;
12365
        using other_array_t = typename BasicJsonType::array_t;
12366
12367
        switch (val.type())
12368
        {
12369
            case value_t::boolean:
12370
                JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
12371
                break;
12372
            case value_t::number_float:
12373
                JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
12374
                break;
12375
            case value_t::number_integer:
12376
                JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
12377
                break;
12378
            case value_t::number_unsigned:
12379
                JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
12380
                break;
12381
            case value_t::string:
12382
                JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
12383
                break;
12384
            case value_t::object:
12385
                JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
12386
                break;
12387
            case value_t::array:
12388
                JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
12389
                break;
12390
            case value_t::null:
12391
                *this = nullptr;
12392
                break;
12393
            case value_t::discarded:
12394
                m_type = value_t::discarded;
12395
                break;
12396
        }
12397
        assert_invariant();
12398
    }
12399
12400
    /*!
12401
    @brief create a container (array or object) from an initializer list
12402
12403
    Creates a JSON value of type array or object from the passed initializer
12404
    list @a init. In case @a type_deduction is `true` (default), the type of
12405
    the JSON value to be created is deducted from the initializer list @a init
12406
    according to the following rules:
12407
12408
    1. If the list is empty, an empty JSON object value `{}` is created.
12409
    2. If the list consists of pairs whose first element is a string, a JSON
12410
       object value is created where the first elements of the pairs are
12411
       treated as keys and the second elements are as values.
12412
    3. In all other cases, an array is created.
12413
12414
    The rules aim to create the best fit between a C++ initializer list and
12415
    JSON values. The rationale is as follows:
12416
12417
    1. The empty initializer list is written as `{}` which is exactly an empty
12418
       JSON object.
12419
    2. C++ has no way of describing mapped types other than to list a list of
12420
       pairs. As JSON requires that keys must be of type string, rule 2 is the
12421
       weakest constraint one can pose on initializer lists to interpret them
12422
       as an object.
12423
    3. In all other cases, the initializer list could not be interpreted as
12424
       JSON object type, so interpreting it as JSON array type is safe.
12425
12426
    With the rules described above, the following JSON values cannot be
12427
    expressed by an initializer list:
12428
12429
    - the empty array (`[]`): use @ref array(initializer_list_t)
12430
      with an empty initializer list in this case
12431
    - arrays whose elements satisfy rule 2: use @ref
12432
      array(initializer_list_t) with the same initializer list
12433
      in this case
12434
12435
    @note When used without parentheses around an empty initializer list, @ref
12436
    basic_json() is called instead of this function, yielding the JSON null
12437
    value.
12438
12439
    @param[in] init  initializer list with JSON values
12440
12441
    @param[in] type_deduction internal parameter; when set to `true`, the type
12442
    of the JSON value is deducted from the initializer list @a init; when set
12443
    to `false`, the type provided via @a manual_type is forced. This mode is
12444
    used by the functions @ref array(initializer_list_t) and
12445
    @ref object(initializer_list_t).
12446
12447
    @param[in] manual_type internal parameter; when @a type_deduction is set
12448
    to `false`, the created JSON value will use the provided type (only @ref
12449
    value_t::array and @ref value_t::object are valid); when @a type_deduction
12450
    is set to `true`, this parameter has no effect
12451
12452
    @throw type_error.301 if @a type_deduction is `false`, @a manual_type is
12453
    `value_t::object`, but @a init contains an element which is not a pair
12454
    whose first element is a string. In this case, the constructor could not
12455
    create an object. If @a type_deduction would have be `true`, an array
12456
    would have been created. See @ref object(initializer_list_t)
12457
    for an example.
12458
12459
    @complexity Linear in the size of the initializer list @a init.
12460
12461
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
12462
    changes to any JSON value.
12463
12464
    @liveexample{The example below shows how JSON values are created from
12465
    initializer lists.,basic_json__list_init_t}
12466
12467
    @sa @ref array(initializer_list_t) -- create a JSON array
12468
    value from an initializer list
12469
    @sa @ref object(initializer_list_t) -- create a JSON object
12470
    value from an initializer list
12471
12472
    @since version 1.0.0
12473
    */
12474
    basic_json(initializer_list_t init,
12475
               bool type_deduction = true,
12476
               value_t manual_type = value_t::array)
12477
    {
12478
        // check if each element is an array with two elements whose first
12479
        // element is a string
12480
        bool is_an_object = std::all_of(init.begin(), init.end(),
12481
                                        [](const detail::json_ref<basic_json>& element_ref)
12482
        {
12483
            return (element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string());
12484
        });
12485
12486
        // adjust type if type deduction is not wanted
12487
        if (not type_deduction)
12488
        {
12489
            // if array is wanted, do not create an object though possible
12490
            if (manual_type == value_t::array)
12491
            {
12492
                is_an_object = false;
12493
            }
12494
12495
            // if object is wanted but impossible, throw an exception
12496
            if (JSON_UNLIKELY(manual_type == value_t::object and not is_an_object))
12497
            {
12498
                JSON_THROW(type_error::create(301, "cannot create object from initializer list"));
12499
            }
12500
        }
12501
12502
        if (is_an_object)
12503
        {
12504
            // the initializer list is a list of pairs -> create object
12505
            m_type = value_t::object;
12506
            m_value = value_t::object;
12507
12508
            std::for_each(init.begin(), init.end(), [this](const detail::json_ref<basic_json>& element_ref)
12509
            {
12510
                auto element = element_ref.moved_or_copied();
12511
                m_value.object->emplace(
12512
                    std::move(*((*element.m_value.array)[0].m_value.string)),
12513
                    std::move((*element.m_value.array)[1]));
12514
            });
12515
        }
12516
        else
12517
        {
12518
            // the initializer list describes an array -> create array
12519
            m_type = value_t::array;
12520
            m_value.array = create<array_t>(init.begin(), init.end());
12521
        }
12522
12523
        assert_invariant();
12524
    }
12525
12526
    /*!
12527
    @brief explicitly create an array from an initializer list
12528
12529
    Creates a JSON array value from a given initializer list. That is, given a
12530
    list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the
12531
    initializer list is empty, the empty array `[]` is created.
12532
12533
    @note This function is only needed to express two edge cases that cannot
12534
    be realized with the initializer list constructor (@ref
12535
    basic_json(initializer_list_t, bool, value_t)). These cases
12536
    are:
12537
    1. creating an array whose elements are all pairs whose first element is a
12538
    string -- in this case, the initializer list constructor would create an
12539
    object, taking the first elements as keys
12540
    2. creating an empty array -- passing the empty initializer list to the
12541
    initializer list constructor yields an empty object
12542
12543
    @param[in] init  initializer list with JSON values to create an array from
12544
    (optional)
12545
12546
    @return JSON array value
12547
12548
    @complexity Linear in the size of @a init.
12549
12550
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
12551
    changes to any JSON value.
12552
12553
    @liveexample{The following code shows an example for the `array`
12554
    function.,array}
12555
12556
    @sa @ref basic_json(initializer_list_t, bool, value_t) --
12557
    create a JSON value from an initializer list
12558
    @sa @ref object(initializer_list_t) -- create a JSON object
12559
    value from an initializer list
12560
12561
    @since version 1.0.0
12562
    */
12563
    static basic_json array(initializer_list_t init = {})
12564
    {
12565
        return basic_json(init, false, value_t::array);
12566
    }
12567
12568
    /*!
12569
    @brief explicitly create an object from an initializer list
12570
12571
    Creates a JSON object value from a given initializer list. The initializer
12572
    lists elements must be pairs, and their first elements must be strings. If
12573
    the initializer list is empty, the empty object `{}` is created.
12574
12575
    @note This function is only added for symmetry reasons. In contrast to the
12576
    related function @ref array(initializer_list_t), there are
12577
    no cases which can only be expressed by this function. That is, any
12578
    initializer list @a init can also be passed to the initializer list
12579
    constructor @ref basic_json(initializer_list_t, bool, value_t).
12580
12581
    @param[in] init  initializer list to create an object from (optional)
12582
12583
    @return JSON object value
12584
12585
    @throw type_error.301 if @a init is not a list of pairs whose first
12586
    elements are strings. In this case, no object can be created. When such a
12587
    value is passed to @ref basic_json(initializer_list_t, bool, value_t),
12588
    an array would have been created from the passed initializer list @a init.
12589
    See example below.
12590
12591
    @complexity Linear in the size of @a init.
12592
12593
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
12594
    changes to any JSON value.
12595
12596
    @liveexample{The following code shows an example for the `object`
12597
    function.,object}
12598
12599
    @sa @ref basic_json(initializer_list_t, bool, value_t) --
12600
    create a JSON value from an initializer list
12601
    @sa @ref array(initializer_list_t) -- create a JSON array
12602
    value from an initializer list
12603
12604
    @since version 1.0.0
12605
    */
12606
    static basic_json object(initializer_list_t init = {})
12607
    {
12608
        return basic_json(init, false, value_t::object);
12609
    }
12610
12611
    /*!
12612
    @brief construct an array with count copies of given value
12613
12614
    Constructs a JSON array value by creating @a cnt copies of a passed value.
12615
    In case @a cnt is `0`, an empty array is created.
12616
12617
    @param[in] cnt  the number of JSON copies of @a val to create
12618
    @param[in] val  the JSON value to copy
12619
12620
    @post `std::distance(begin(),end()) == cnt` holds.
12621
12622
    @complexity Linear in @a cnt.
12623
12624
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
12625
    changes to any JSON value.
12626
12627
    @liveexample{The following code shows examples for the @ref
12628
    basic_json(size_type\, const basic_json&)
12629
    constructor.,basic_json__size_type_basic_json}
12630
12631
    @since version 1.0.0
12632
    */
12633
    basic_json(size_type cnt, const basic_json& val)
12634
        : m_type(value_t::array)
12635
    {
12636
        m_value.array = create<array_t>(cnt, val);
12637
        assert_invariant();
12638
    }
12639
12640
    /*!
12641
    @brief construct a JSON container given an iterator range
12642
12643
    Constructs the JSON value with the contents of the range `[first, last)`.
12644
    The semantics depends on the different types a JSON value can have:
12645
    - In case of a null type, invalid_iterator.206 is thrown.
12646
    - In case of other primitive types (number, boolean, or string), @a first
12647
      must be `begin()` and @a last must be `end()`. In this case, the value is
12648
      copied. Otherwise, invalid_iterator.204 is thrown.
12649
    - In case of structured types (array, object), the constructor behaves as
12650
      similar versions for `std::vector` or `std::map`; that is, a JSON array
12651
      or object is constructed from the values in the range.
12652
12653
    @tparam InputIT an input iterator type (@ref iterator or @ref
12654
    const_iterator)
12655
12656
    @param[in] first begin of the range to copy from (included)
12657
    @param[in] last end of the range to copy from (excluded)
12658
12659
    @pre Iterators @a first and @a last must be initialized. **This
12660
         precondition is enforced with an assertion (see warning).** If
12661
         assertions are switched off, a violation of this precondition yields
12662
         undefined behavior.
12663
12664
    @pre Range `[first, last)` is valid. Usually, this precondition cannot be
12665
         checked efficiently. Only certain edge cases are detected; see the
12666
         description of the exceptions below. A violation of this precondition
12667
         yields undefined behavior.
12668
12669
    @warning A precondition is enforced with a runtime assertion that will
12670
             result in calling `std::abort` if this precondition is not met.
12671
             Assertions can be disabled by defining `NDEBUG` at compile time.
12672
             See https://en.cppreference.com/w/cpp/error/assert for more
12673
             information.
12674
12675
    @throw invalid_iterator.201 if iterators @a first and @a last are not
12676
    compatible (i.e., do not belong to the same JSON value). In this case,
12677
    the range `[first, last)` is undefined.
12678
    @throw invalid_iterator.204 if iterators @a first and @a last belong to a
12679
    primitive type (number, boolean, or string), but @a first does not point
12680
    to the first element any more. In this case, the range `[first, last)` is
12681
    undefined. See example code below.
12682
    @throw invalid_iterator.206 if iterators @a first and @a last belong to a
12683
    null value. In this case, the range `[first, last)` is undefined.
12684
12685
    @complexity Linear in distance between @a first and @a last.
12686
12687
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
12688
    changes to any JSON value.
12689
12690
    @liveexample{The example below shows several ways to create JSON values by
12691
    specifying a subrange with iterators.,basic_json__InputIt_InputIt}
12692
12693
    @since version 1.0.0
12694
    */
12695
    template<class InputIT, typename std::enable_if<
12696
                 std::is_same<InputIT, typename basic_json_t::iterator>::value or
12697
                 std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>
12698
    basic_json(InputIT first, InputIT last)
12699
    {
12700
        assert(first.m_object != nullptr);
12701
        assert(last.m_object != nullptr);
12702
12703
        // make sure iterator fits the current value
12704
        if (JSON_UNLIKELY(first.m_object != last.m_object))
12705
        {
12706
            JSON_THROW(invalid_iterator::create(201, "iterators are not compatible"));
12707
        }
12708
12709
        // copy type from first iterator
12710
        m_type = first.m_object->m_type;
12711
12712
        // check if iterator range is complete for primitive values
12713
        switch (m_type)
12714
        {
12715
            case value_t::boolean:
12716
            case value_t::number_float:
12717
            case value_t::number_integer:
12718
            case value_t::number_unsigned:
12719
            case value_t::string:
12720
            {
12721
                if (JSON_UNLIKELY(not first.m_it.primitive_iterator.is_begin()
12722
                                  or not last.m_it.primitive_iterator.is_end()))
12723
                {
12724
                    JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
12725
                }
12726
                break;
12727
            }
12728
12729
            default:
12730
                break;
12731
        }
12732
12733
        switch (m_type)
12734
        {
12735
            case value_t::number_integer:
12736
            {
12737
                m_value.number_integer = first.m_object->m_value.number_integer;
12738
                break;
12739
            }
12740
12741
            case value_t::number_unsigned:
12742
            {
12743
                m_value.number_unsigned = first.m_object->m_value.number_unsigned;
12744
                break;
12745
            }
12746
12747
            case value_t::number_float:
12748
            {
12749
                m_value.number_float = first.m_object->m_value.number_float;
12750
                break;
12751
            }
12752
12753
            case value_t::boolean:
12754
            {
12755
                m_value.boolean = first.m_object->m_value.boolean;
12756
                break;
12757
            }
12758
12759
            case value_t::string:
12760
            {
12761
                m_value = *first.m_object->m_value.string;
12762
                break;
12763
            }
12764
12765
            case value_t::object:
12766
            {
12767
                m_value.object = create<object_t>(first.m_it.object_iterator,
12768
                                                  last.m_it.object_iterator);
12769
                break;
12770
            }
12771
12772
            case value_t::array:
12773
            {
12774
                m_value.array = create<array_t>(first.m_it.array_iterator,
12775
                                                last.m_it.array_iterator);
12776
                break;
12777
            }
12778
12779
            default:
12780
                JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " +
12781
                                                    std::string(first.m_object->type_name())));
12782
        }
12783
12784
        assert_invariant();
12785
    }
12786
12787
12788
    ///////////////////////////////////////
12789
    // other constructors and destructor //
12790
    ///////////////////////////////////////
12791
12792
    /// @private
12793
    basic_json(const detail::json_ref<basic_json>& ref)
12794
        : basic_json(ref.moved_or_copied())
12795
    {}
12796
12797
    /*!
12798
    @brief copy constructor
12799
12800
    Creates a copy of a given JSON value.
12801
12802
    @param[in] other  the JSON value to copy
12803
12804
    @post `*this == other`
12805
12806
    @complexity Linear in the size of @a other.
12807
12808
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
12809
    changes to any JSON value.
12810
12811
    @requirement This function helps `basic_json` satisfying the
12812
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
12813
    requirements:
12814
    - The complexity is linear.
12815
    - As postcondition, it holds: `other == basic_json(other)`.
12816
12817
    @liveexample{The following code shows an example for the copy
12818
    constructor.,basic_json__basic_json}
12819
12820
    @since version 1.0.0
12821
    */
12822
    basic_json(const basic_json& other)
12823
        : m_type(other.m_type)
12824
173k
    {
12825
173k
        // check of passed value is valid
12826
173k
        other.assert_invariant();
12827
173k
12828
173k
        switch (m_type)
12829
173k
        {
12830
173k
            case value_t::object:
12831
23.4k
            {
12832
23.4k
                m_value = *other.m_value.object;
12833
23.4k
                break;
12834
173k
            }
12835
173k
12836
173k
            case value_t::array:
12837
96
            {
12838
96
                m_value = *other.m_value.array;
12839
96
                break;
12840
173k
            }
12841
173k
12842
173k
            case value_t::string:
12843
123k
            {
12844
123k
                m_value = *other.m_value.string;
12845
123k
                break;
12846
173k
            }
12847
173k
12848
173k
            case value_t::boolean:
12849
48
            {
12850
48
                m_value = other.m_value.boolean;
12851
48
                break;
12852
173k
            }
12853
173k
12854
173k
            case value_t::number_integer:
12855
1.68k
            {
12856
1.68k
                m_value = other.m_value.number_integer;
12857
1.68k
                break;
12858
173k
            }
12859
173k
12860
173k
            case value_t::number_unsigned:
12861
14.6k
            {
12862
14.6k
                m_value = other.m_value.number_unsigned;
12863
14.6k
                break;
12864
173k
            }
12865
173k
12866
173k
            case value_t::number_float:
12867
10.5k
            {
12868
10.5k
                m_value = other.m_value.number_float;
12869
10.5k
                break;
12870
173k
            }
12871
173k
12872
173k
            default:
12873
32
                break;
12874
173k
        }
12875
173k
12876
173k
        assert_invariant();
12877
173k
    }
12878
12879
    /*!
12880
    @brief move constructor
12881
12882
    Move constructor. Constructs a JSON value with the contents of the given
12883
    value @a other using move semantics. It "steals" the resources from @a
12884
    other and leaves it as JSON null value.
12885
12886
    @param[in,out] other  value to move to this object
12887
12888
    @post `*this` has the same value as @a other before the call.
12889
    @post @a other is a JSON null value.
12890
12891
    @complexity Constant.
12892
12893
    @exceptionsafety No-throw guarantee: this constructor never throws
12894
    exceptions.
12895
12896
    @requirement This function helps `basic_json` satisfying the
12897
    [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible)
12898
    requirements.
12899
12900
    @liveexample{The code below shows the move constructor explicitly called
12901
    via std::move.,basic_json__moveconstructor}
12902
12903
    @since version 1.0.0
12904
    */
12905
    basic_json(basic_json&& other) noexcept
12906
        : m_type(std::move(other.m_type)),
12907
          m_value(std::move(other.m_value))
12908
50.4k
    {
12909
50.4k
        // check that passed value is valid
12910
50.4k
        other.assert_invariant();
12911
50.4k
12912
50.4k
        // invalidate payload
12913
50.4k
        other.m_type = value_t::null;
12914
50.4k
        other.m_value = {};
12915
50.4k
12916
50.4k
        assert_invariant();
12917
50.4k
    }
12918
12919
    /*!
12920
    @brief copy assignment
12921
12922
    Copy assignment operator. Copies a JSON value via the "copy and swap"
12923
    strategy: It is expressed in terms of the copy constructor, destructor,
12924
    and the `swap()` member function.
12925
12926
    @param[in] other  value to copy from
12927
12928
    @complexity Linear.
12929
12930
    @requirement This function helps `basic_json` satisfying the
12931
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
12932
    requirements:
12933
    - The complexity is linear.
12934
12935
    @liveexample{The code below shows and example for the copy assignment. It
12936
    creates a copy of value `a` which is then swapped with `b`. Finally\, the
12937
    copy of `a` (which is the null value after the swap) is
12938
    destroyed.,basic_json__copyassignment}
12939
12940
    @since version 1.0.0
12941
    */
12942
    reference& operator=(basic_json other) noexcept (
12943
        std::is_nothrow_move_constructible<value_t>::value and
12944
        std::is_nothrow_move_assignable<value_t>::value and
12945
        std::is_nothrow_move_constructible<json_value>::value and
12946
        std::is_nothrow_move_assignable<json_value>::value
12947
    )
12948
1.02M
    {
12949
1.02M
        // check that passed value is valid
12950
1.02M
        other.assert_invariant();
12951
1.02M
12952
1.02M
        using std::swap;
12953
1.02M
        swap(m_type, other.m_type);
12954
1.02M
        swap(m_value, other.m_value);
12955
1.02M
12956
1.02M
        assert_invariant();
12957
1.02M
        return *this;
12958
1.02M
    }
12959
12960
    /*!
12961
    @brief destructor
12962
12963
    Destroys the JSON value and frees all allocated memory.
12964
12965
    @complexity Linear.
12966
12967
    @requirement This function helps `basic_json` satisfying the
12968
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
12969
    requirements:
12970
    - The complexity is linear.
12971
    - All stored elements are destroyed and all memory is freed.
12972
12973
    @since version 1.0.0
12974
    */
12975
    ~basic_json() noexcept
12976
2.30M
    {
12977
2.30M
        assert_invariant();
12978
2.30M
        m_value.destroy(m_type);
12979
2.30M
    }
12980
12981
    /// @}
12982
12983
  public:
12984
    ///////////////////////
12985
    // object inspection //
12986
    ///////////////////////
12987
12988
    /// @name object inspection
12989
    /// Functions to inspect the type of a JSON value.
12990
    /// @{
12991
12992
    /*!
12993
    @brief serialization
12994
12995
    Serialization function for JSON values. The function tries to mimic
12996
    Python's `json.dumps()` function, and currently supports its @a indent
12997
    and @a ensure_ascii parameters.
12998
12999
    @param[in] indent If indent is nonnegative, then array elements and object
13000
    members will be pretty-printed with that indent level. An indent level of
13001
    `0` will only insert newlines. `-1` (the default) selects the most compact
13002
    representation.
13003
    @param[in] indent_char The character to use for indentation if @a indent is
13004
    greater than `0`. The default is ` ` (space).
13005
    @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters
13006
    in the output are escaped with `\uXXXX` sequences, and the result consists
13007
    of ASCII characters only.
13008
13009
    @return string containing the serialization of the JSON value
13010
13011
    @throw type_error.316 if a string stored inside the JSON value is not
13012
                          UTF-8 encoded
13013
13014
    @complexity Linear.
13015
13016
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
13017
    changes in the JSON value.
13018
13019
    @liveexample{The following example shows the effect of different @a indent\,
13020
    @a indent_char\, and @a ensure_ascii parameters to the result of the
13021
    serialization.,dump}
13022
13023
    @see https://docs.python.org/2/library/json.html#json.dump
13024
13025
    @since version 1.0.0; indentation character @a indent_char, option
13026
           @a ensure_ascii and exceptions added in version 3.0.0
13027
    */
13028
    string_t dump(const int indent = -1, const char indent_char = ' ',
13029
                  const bool ensure_ascii = false) const
13030
72
    {
13031
72
        string_t result;
13032
72
        serializer s(detail::output_adapter<char, string_t>(result), indent_char);
13033
72
13034
72
        if (indent >= 0)
13035
64
        {
13036
64
            s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));
13037
64
        }
13038
8
        else
13039
8
        {
13040
8
            s.dump(*this, false, ensure_ascii, 0);
13041
8
        }
13042
72
13043
72
        return result;
13044
72
    }
13045
13046
    /*!
13047
    @brief return the type of the JSON value (explicit)
13048
13049
    Return the type of the JSON value as a value from the @ref value_t
13050
    enumeration.
13051
13052
    @return the type of the JSON value
13053
            Value type                | return value
13054
            ------------------------- | -------------------------
13055
            null                      | value_t::null
13056
            boolean                   | value_t::boolean
13057
            string                    | value_t::string
13058
            number (integer)          | value_t::number_integer
13059
            number (unsigned integer) | value_t::number_unsigned
13060
            number (floating-point)   | value_t::number_float
13061
            object                    | value_t::object
13062
            array                     | value_t::array
13063
            discarded                 | value_t::discarded
13064
13065
    @complexity Constant.
13066
13067
    @exceptionsafety No-throw guarantee: this member function never throws
13068
    exceptions.
13069
13070
    @liveexample{The following code exemplifies `type()` for all JSON
13071
    types.,type}
13072
13073
    @sa @ref operator value_t() -- return the type of the JSON value (implicit)
13074
    @sa @ref type_name() -- return the type as string
13075
13076
    @since version 1.0.0
13077
    */
13078
    constexpr value_t type() const noexcept
13079
80
    {
13080
80
        return m_type;
13081
80
    }
13082
13083
    /*!
13084
    @brief return whether type is primitive
13085
13086
    This function returns true if and only if the JSON type is primitive
13087
    (string, number, boolean, or null).
13088
13089
    @return `true` if type is primitive (string, number, boolean, or null),
13090
    `false` otherwise.
13091
13092
    @complexity Constant.
13093
13094
    @exceptionsafety No-throw guarantee: this member function never throws
13095
    exceptions.
13096
13097
    @liveexample{The following code exemplifies `is_primitive()` for all JSON
13098
    types.,is_primitive}
13099
13100
    @sa @ref is_structured() -- returns whether JSON value is structured
13101
    @sa @ref is_null() -- returns whether JSON value is `null`
13102
    @sa @ref is_string() -- returns whether JSON value is a string
13103
    @sa @ref is_boolean() -- returns whether JSON value is a boolean
13104
    @sa @ref is_number() -- returns whether JSON value is a number
13105
13106
    @since version 1.0.0
13107
    */
13108
    constexpr bool is_primitive() const noexcept
13109
    {
13110
        return is_null() or is_string() or is_boolean() or is_number();
13111
    }
13112
13113
    /*!
13114
    @brief return whether type is structured
13115
13116
    This function returns true if and only if the JSON type is structured
13117
    (array or object).
13118
13119
    @return `true` if type is structured (array or object), `false` otherwise.
13120
13121
    @complexity Constant.
13122
13123
    @exceptionsafety No-throw guarantee: this member function never throws
13124
    exceptions.
13125
13126
    @liveexample{The following code exemplifies `is_structured()` for all JSON
13127
    types.,is_structured}
13128
13129
    @sa @ref is_primitive() -- returns whether value is primitive
13130
    @sa @ref is_array() -- returns whether value is an array
13131
    @sa @ref is_object() -- returns whether value is an object
13132
13133
    @since version 1.0.0
13134
    */
13135
    constexpr bool is_structured() const noexcept
13136
    {
13137
        return is_array() or is_object();
13138
    }
13139
13140
    /*!
13141
    @brief return whether value is null
13142
13143
    This function returns true if and only if the JSON value is null.
13144
13145
    @return `true` if type is null, `false` otherwise.
13146
13147
    @complexity Constant.
13148
13149
    @exceptionsafety No-throw guarantee: this member function never throws
13150
    exceptions.
13151
13152
    @liveexample{The following code exemplifies `is_null()` for all JSON
13153
    types.,is_null}
13154
13155
    @since version 1.0.0
13156
    */
13157
    constexpr bool is_null() const noexcept
13158
6.64k
    {
13159
6.64k
        return (m_type == value_t::null);
13160
6.64k
    }
13161
13162
    /*!
13163
    @brief return whether value is a boolean
13164
13165
    This function returns true if and only if the JSON value is a boolean.
13166
13167
    @return `true` if type is boolean, `false` otherwise.
13168
13169
    @complexity Constant.
13170
13171
    @exceptionsafety No-throw guarantee: this member function never throws
13172
    exceptions.
13173
13174
    @liveexample{The following code exemplifies `is_boolean()` for all JSON
13175
    types.,is_boolean}
13176
13177
    @since version 1.0.0
13178
    */
13179
    constexpr bool is_boolean() const noexcept
13180
16
    {
13181
16
        return (m_type == value_t::boolean);
13182
16
    }
13183
13184
    /*!
13185
    @brief return whether value is a number
13186
13187
    This function returns true if and only if the JSON value is a number. This
13188
    includes both integer (signed and unsigned) and floating-point values.
13189
13190
    @return `true` if type is number (regardless whether integer, unsigned
13191
    integer or floating-type), `false` otherwise.
13192
13193
    @complexity Constant.
13194
13195
    @exceptionsafety No-throw guarantee: this member function never throws
13196
    exceptions.
13197
13198
    @liveexample{The following code exemplifies `is_number()` for all JSON
13199
    types.,is_number}
13200
13201
    @sa @ref is_number_integer() -- check if value is an integer or unsigned
13202
    integer number
13203
    @sa @ref is_number_unsigned() -- check if value is an unsigned integer
13204
    number
13205
    @sa @ref is_number_float() -- check if value is a floating-point number
13206
13207
    @since version 1.0.0
13208
    */
13209
    constexpr bool is_number() const noexcept
13210
    {
13211
        return is_number_integer() or is_number_float();
13212
    }
13213
13214
    /*!
13215
    @brief return whether value is an integer number
13216
13217
    This function returns true if and only if the JSON value is a signed or
13218
    unsigned integer number. This excludes floating-point values.
13219
13220
    @return `true` if type is an integer or unsigned integer number, `false`
13221
    otherwise.
13222
13223
    @complexity Constant.
13224
13225
    @exceptionsafety No-throw guarantee: this member function never throws
13226
    exceptions.
13227
13228
    @liveexample{The following code exemplifies `is_number_integer()` for all
13229
    JSON types.,is_number_integer}
13230
13231
    @sa @ref is_number() -- check if value is a number
13232
    @sa @ref is_number_unsigned() -- check if value is an unsigned integer
13233
    number
13234
    @sa @ref is_number_float() -- check if value is a floating-point number
13235
13236
    @since version 1.0.0
13237
    */
13238
    constexpr bool is_number_integer() const noexcept
13239
0
    {
13240
0
        return (m_type == value_t::number_integer or m_type == value_t::number_unsigned);
13241
0
    }
13242
13243
    /*!
13244
    @brief return whether value is an unsigned integer number
13245
13246
    This function returns true if and only if the JSON value is an unsigned
13247
    integer number. This excludes floating-point and signed integer values.
13248
13249
    @return `true` if type is an unsigned integer number, `false` otherwise.
13250
13251
    @complexity Constant.
13252
13253
    @exceptionsafety No-throw guarantee: this member function never throws
13254
    exceptions.
13255
13256
    @liveexample{The following code exemplifies `is_number_unsigned()` for all
13257
    JSON types.,is_number_unsigned}
13258
13259
    @sa @ref is_number() -- check if value is a number
13260
    @sa @ref is_number_integer() -- check if value is an integer or unsigned
13261
    integer number
13262
    @sa @ref is_number_float() -- check if value is a floating-point number
13263
13264
    @since version 2.0.0
13265
    */
13266
    constexpr bool is_number_unsigned() const noexcept
13267
608
    {
13268
608
        return (m_type == value_t::number_unsigned);
13269
608
    }
13270
13271
    /*!
13272
    @brief return whether value is a floating-point number
13273
13274
    This function returns true if and only if the JSON value is a
13275
    floating-point number. This excludes signed and unsigned integer values.
13276
13277
    @return `true` if type is a floating-point number, `false` otherwise.
13278
13279
    @complexity Constant.
13280
13281
    @exceptionsafety No-throw guarantee: this member function never throws
13282
    exceptions.
13283
13284
    @liveexample{The following code exemplifies `is_number_float()` for all
13285
    JSON types.,is_number_float}
13286
13287
    @sa @ref is_number() -- check if value is number
13288
    @sa @ref is_number_integer() -- check if value is an integer number
13289
    @sa @ref is_number_unsigned() -- check if value is an unsigned integer
13290
    number
13291
13292
    @since version 1.0.0
13293
    */
13294
    constexpr bool is_number_float() const noexcept
13295
592
    {
13296
592
        return (m_type == value_t::number_float);
13297
592
    }
13298
13299
    /*!
13300
    @brief return whether value is an object
13301
13302
    This function returns true if and only if the JSON value is an object.
13303
13304
    @return `true` if type is object, `false` otherwise.
13305
13306
    @complexity Constant.
13307
13308
    @exceptionsafety No-throw guarantee: this member function never throws
13309
    exceptions.
13310
13311
    @liveexample{The following code exemplifies `is_object()` for all JSON
13312
    types.,is_object}
13313
13314
    @since version 1.0.0
13315
    */
13316
    constexpr bool is_object() const noexcept
13317
1.06M
    {
13318
1.06M
        return (m_type == value_t::object);
13319
1.06M
    }
13320
13321
    /*!
13322
    @brief return whether value is an array
13323
13324
    This function returns true if and only if the JSON value is an array.
13325
13326
    @return `true` if type is array, `false` otherwise.
13327
13328
    @complexity Constant.
13329
13330
    @exceptionsafety No-throw guarantee: this member function never throws
13331
    exceptions.
13332
13333
    @liveexample{The following code exemplifies `is_array()` for all JSON
13334
    types.,is_array}
13335
13336
    @since version 1.0.0
13337
    */
13338
    constexpr bool is_array() const noexcept
13339
2.09M
    {
13340
2.09M
        return (m_type == value_t::array);
13341
2.09M
    }
13342
13343
    /*!
13344
    @brief return whether value is a string
13345
13346
    This function returns true if and only if the JSON value is a string.
13347
13348
    @return `true` if type is string, `false` otherwise.
13349
13350
    @complexity Constant.
13351
13352
    @exceptionsafety No-throw guarantee: this member function never throws
13353
    exceptions.
13354
13355
    @liveexample{The following code exemplifies `is_string()` for all JSON
13356
    types.,is_string}
13357
13358
    @since version 1.0.0
13359
    */
13360
    constexpr bool is_string() const noexcept
13361
93.0k
    {
13362
93.0k
        return (m_type == value_t::string);
13363
93.0k
    }
13364
13365
    /*!
13366
    @brief return whether value is discarded
13367
13368
    This function returns true if and only if the JSON value was discarded
13369
    during parsing with a callback function (see @ref parser_callback_t).
13370
13371
    @note This function will always be `false` for JSON values after parsing.
13372
    That is, discarded values can only occur during parsing, but will be
13373
    removed when inside a structured value or replaced by null in other cases.
13374
13375
    @return `true` if type is discarded, `false` otherwise.
13376
13377
    @complexity Constant.
13378
13379
    @exceptionsafety No-throw guarantee: this member function never throws
13380
    exceptions.
13381
13382
    @liveexample{The following code exemplifies `is_discarded()` for all JSON
13383
    types.,is_discarded}
13384
13385
    @since version 1.0.0
13386
    */
13387
    constexpr bool is_discarded() const noexcept
13388
0
    {
13389
0
        return (m_type == value_t::discarded);
13390
0
    }
13391
13392
    /*!
13393
    @brief return the type of the JSON value (implicit)
13394
13395
    Implicitly return the type of the JSON value as a value from the @ref
13396
    value_t enumeration.
13397
13398
    @return the type of the JSON value
13399
13400
    @complexity Constant.
13401
13402
    @exceptionsafety No-throw guarantee: this member function never throws
13403
    exceptions.
13404
13405
    @liveexample{The following code exemplifies the @ref value_t operator for
13406
    all JSON types.,operator__value_t}
13407
13408
    @sa @ref type() -- return the type of the JSON value (explicit)
13409
    @sa @ref type_name() -- return the type as string
13410
13411
    @since version 1.0.0
13412
    */
13413
    constexpr operator value_t() const noexcept
13414
1.20k
    {
13415
1.20k
        return m_type;
13416
1.20k
    }
13417
13418
    /// @}
13419
13420
  private:
13421
    //////////////////
13422
    // value access //
13423
    //////////////////
13424
13425
    /// get a boolean (explicit)
13426
    boolean_t get_impl(boolean_t* /*unused*/) const
13427
    {
13428
        if (JSON_LIKELY(is_boolean()))
13429
        {
13430
            return m_value.boolean;
13431
        }
13432
13433
        JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name())));
13434
    }
13435
13436
    /// get a pointer to the value (object)
13437
    object_t* get_impl_ptr(object_t* /*unused*/) noexcept
13438
    {
13439
        return is_object() ? m_value.object : nullptr;
13440
    }
13441
13442
    /// get a pointer to the value (object)
13443
    constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
13444
    {
13445
        return is_object() ? m_value.object : nullptr;
13446
    }
13447
13448
    /// get a pointer to the value (array)
13449
    array_t* get_impl_ptr(array_t* /*unused*/) noexcept
13450
    {
13451
        return is_array() ? m_value.array : nullptr;
13452
    }
13453
13454
    /// get a pointer to the value (array)
13455
    constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
13456
    {
13457
        return is_array() ? m_value.array : nullptr;
13458
    }
13459
13460
    /// get a pointer to the value (string)
13461
    string_t* get_impl_ptr(string_t* /*unused*/) noexcept
13462
    {
13463
        return is_string() ? m_value.string : nullptr;
13464
    }
13465
13466
    /// get a pointer to the value (string)
13467
    constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept
13468
46.5k
    {
13469
46.5k
        return is_string() ? m_value.string : nullptr;
13470
46.5k
    }
13471
13472
    /// get a pointer to the value (boolean)
13473
    boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept
13474
    {
13475
        return is_boolean() ? &m_value.boolean : nullptr;
13476
    }
13477
13478
    /// get a pointer to the value (boolean)
13479
    constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept
13480
8
    {
13481
8
        return is_boolean() ? &m_value.boolean : nullptr;
13482
8
    }
13483
13484
    /// get a pointer to the value (integer number)
13485
    number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
13486
    {
13487
        return is_number_integer() ? &m_value.number_integer : nullptr;
13488
    }
13489
13490
    /// get a pointer to the value (integer number)
13491
    constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
13492
0
    {
13493
0
        return is_number_integer() ? &m_value.number_integer : nullptr;
13494
0
    }
13495
13496
    /// get a pointer to the value (unsigned number)
13497
    number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept
13498
    {
13499
        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
13500
    }
13501
13502
    /// get a pointer to the value (unsigned number)
13503
    constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
13504
608
    {
13505
608
        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
13506
608
    }
13507
13508
    /// get a pointer to the value (floating-point number)
13509
    number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept
13510
    {
13511
        return is_number_float() ? &m_value.number_float : nullptr;
13512
    }
13513
13514
    /// get a pointer to the value (floating-point number)
13515
    constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept
13516
592
    {
13517
592
        return is_number_float() ? &m_value.number_float : nullptr;
13518
592
    }
13519
13520
    /*!
13521
    @brief helper function to implement get_ref()
13522
13523
    This function helps to implement get_ref() without code duplication for
13524
    const and non-const overloads
13525
13526
    @tparam ThisType will be deduced as `basic_json` or `const basic_json`
13527
13528
    @throw type_error.303 if ReferenceType does not match underlying value
13529
    type of the current JSON
13530
    */
13531
    template<typename ReferenceType, typename ThisType>
13532
    static ReferenceType get_ref_impl(ThisType& obj)
13533
    {
13534
        // delegate the call to get_ptr<>()
13535
        auto ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();
13536
13537
        if (JSON_LIKELY(ptr != nullptr))
13538
        {
13539
            return *ptr;
13540
        }
13541
13542
        JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name())));
13543
    }
13544
13545
  public:
13546
    /// @name value access
13547
    /// Direct access to the stored value of a JSON value.
13548
    /// @{
13549
13550
    /*!
13551
    @brief get special-case overload
13552
13553
    This overloads avoids a lot of template boilerplate, it can be seen as the
13554
    identity method
13555
13556
    @tparam BasicJsonType == @ref basic_json
13557
13558
    @return a copy of *this
13559
13560
    @complexity Constant.
13561
13562
    @since version 2.1.0
13563
    */
13564
    template<typename BasicJsonType, detail::enable_if_t<
13565
                 std::is_same<typename std::remove_const<BasicJsonType>::type, basic_json_t>::value,
13566
                 int> = 0>
13567
    basic_json get() const
13568
48
    {
13569
48
        return *this;
13570
48
    }
13571
13572
    /*!
13573
    @brief get special-case overload
13574
13575
    This overloads converts the current @ref basic_json in a different
13576
    @ref basic_json type
13577
13578
    @tparam BasicJsonType == @ref basic_json
13579
13580
    @return a copy of *this, converted into @tparam BasicJsonType
13581
13582
    @complexity Depending on the implementation of the called `from_json()`
13583
                method.
13584
13585
    @since version 3.2.0
13586
    */
13587
    template<typename BasicJsonType, detail::enable_if_t<
13588
                 not std::is_same<BasicJsonType, basic_json>::value and
13589
                 detail::is_basic_json<BasicJsonType>::value, int> = 0>
13590
    BasicJsonType get() const
13591
    {
13592
        return *this;
13593
    }
13594
13595
    /*!
13596
    @brief get a value (explicit)
13597
13598
    Explicit type conversion between the JSON value and a compatible value
13599
    which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
13600
    and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
13601
    The value is converted by calling the @ref json_serializer<ValueType>
13602
    `from_json()` method.
13603
13604
    The function is equivalent to executing
13605
    @code {.cpp}
13606
    ValueType ret;
13607
    JSONSerializer<ValueType>::from_json(*this, ret);
13608
    return ret;
13609
    @endcode
13610
13611
    This overloads is chosen if:
13612
    - @a ValueType is not @ref basic_json,
13613
    - @ref json_serializer<ValueType> has a `from_json()` method of the form
13614
      `void from_json(const basic_json&, ValueType&)`, and
13615
    - @ref json_serializer<ValueType> does not have a `from_json()` method of
13616
      the form `ValueType from_json(const basic_json&)`
13617
13618
    @tparam ValueTypeCV the provided value type
13619
    @tparam ValueType the returned value type
13620
13621
    @return copy of the JSON value, converted to @a ValueType
13622
13623
    @throw what @ref json_serializer<ValueType> `from_json()` method throws
13624
13625
    @liveexample{The example below shows several conversions from JSON values
13626
    to other types. There a few things to note: (1) Floating-point numbers can
13627
    be converted to integers\, (2) A JSON array can be converted to a standard
13628
    `std::vector<short>`\, (3) A JSON object can be converted to C++
13629
    associative containers such as `std::unordered_map<std::string\,
13630
    json>`.,get__ValueType_const}
13631
13632
    @since version 2.1.0
13633
    */
13634
    template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
13635
             detail::enable_if_t <
13636
                 not detail::is_basic_json<ValueType>::value and
13637
                 detail::has_from_json<basic_json_t, ValueType>::value and
13638
                 not detail::has_non_default_from_json<basic_json_t, ValueType>::value,
13639
                 int> = 0>
13640
    ValueType get() const noexcept(noexcept(
13641
                                       JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))
13642
47.7k
    {
13643
47.7k
        // we cannot static_assert on ValueTypeCV being non-const, because
13644
47.7k
        // there is support for get<const basic_json_t>(), which is why we
13645
47.7k
        // still need the uncvref
13646
47.7k
        static_assert(not std::is_reference<ValueTypeCV>::value,
13647
47.7k
                      "get() cannot be used with reference types, you might want to use get_ref()");
13648
47.7k
        static_assert(std::is_default_constructible<ValueType>::value,
13649
47.7k
                      "types must be DefaultConstructible when used with get()");
13650
47.7k
13651
47.7k
        ValueType ret;
13652
47.7k
        JSONSerializer<ValueType>::from_json(*this, ret);
13653
47.7k
        return ret;
13654
47.7k
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE3getIbbLi0EEET0_v
Line
Count
Source
13642
8
    {
13643
8
        // we cannot static_assert on ValueTypeCV being non-const, because
13644
8
        // there is support for get<const basic_json_t>(), which is why we
13645
8
        // still need the uncvref
13646
8
        static_assert(not std::is_reference<ValueTypeCV>::value,
13647
8
                      "get() cannot be used with reference types, you might want to use get_ref()");
13648
8
        static_assert(std::is_default_constructible<ValueType>::value,
13649
8
                      "types must be DefaultConstructible when used with get()");
13650
8
13651
8
        ValueType ret;
13652
8
        JSONSerializer<ValueType>::from_json(*this, ret);
13653
8
        return ret;
13654
8
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE3getIS8_S8_Li0EEET0_v
Line
Count
Source
13642
46.5k
    {
13643
46.5k
        // we cannot static_assert on ValueTypeCV being non-const, because
13644
46.5k
        // there is support for get<const basic_json_t>(), which is why we
13645
46.5k
        // still need the uncvref
13646
46.5k
        static_assert(not std::is_reference<ValueTypeCV>::value,
13647
46.5k
                      "get() cannot be used with reference types, you might want to use get_ref()");
13648
46.5k
        static_assert(std::is_default_constructible<ValueType>::value,
13649
46.5k
                      "types must be DefaultConstructible when used with get()");
13650
46.5k
13651
46.5k
        ValueType ret;
13652
46.5k
        JSONSerializer<ValueType>::from_json(*this, ret);
13653
46.5k
        return ret;
13654
46.5k
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE3getIiiLi0EEET0_v
Line
Count
Source
13642
608
    {
13643
608
        // we cannot static_assert on ValueTypeCV being non-const, because
13644
608
        // there is support for get<const basic_json_t>(), which is why we
13645
608
        // still need the uncvref
13646
608
        static_assert(not std::is_reference<ValueTypeCV>::value,
13647
608
                      "get() cannot be used with reference types, you might want to use get_ref()");
13648
608
        static_assert(std::is_default_constructible<ValueType>::value,
13649
608
                      "types must be DefaultConstructible when used with get()");
13650
608
13651
608
        ValueType ret;
13652
608
        JSONSerializer<ValueType>::from_json(*this, ret);
13653
608
        return ret;
13654
608
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE3getIddLi0EEET0_v
Line
Count
Source
13642
592
    {
13643
592
        // we cannot static_assert on ValueTypeCV being non-const, because
13644
592
        // there is support for get<const basic_json_t>(), which is why we
13645
592
        // still need the uncvref
13646
592
        static_assert(not std::is_reference<ValueTypeCV>::value,
13647
592
                      "get() cannot be used with reference types, you might want to use get_ref()");
13648
592
        static_assert(std::is_default_constructible<ValueType>::value,
13649
592
                      "types must be DefaultConstructible when used with get()");
13650
592
13651
592
        ValueType ret;
13652
592
        JSONSerializer<ValueType>::from_json(*this, ret);
13653
592
        return ret;
13654
592
    }
13655
13656
    /*!
13657
    @brief get a value (explicit); special case
13658
13659
    Explicit type conversion between the JSON value and a compatible value
13660
    which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
13661
    and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
13662
    The value is converted by calling the @ref json_serializer<ValueType>
13663
    `from_json()` method.
13664
13665
    The function is equivalent to executing
13666
    @code {.cpp}
13667
    return JSONSerializer<ValueTypeCV>::from_json(*this);
13668
    @endcode
13669
13670
    This overloads is chosen if:
13671
    - @a ValueType is not @ref basic_json and
13672
    - @ref json_serializer<ValueType> has a `from_json()` method of the form
13673
      `ValueType from_json(const basic_json&)`
13674
13675
    @note If @ref json_serializer<ValueType> has both overloads of
13676
    `from_json()`, this one is chosen.
13677
13678
    @tparam ValueTypeCV the provided value type
13679
    @tparam ValueType the returned value type
13680
13681
    @return copy of the JSON value, converted to @a ValueType
13682
13683
    @throw what @ref json_serializer<ValueType> `from_json()` method throws
13684
13685
    @since version 2.1.0
13686
    */
13687
    template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
13688
             detail::enable_if_t<not std::is_same<basic_json_t, ValueType>::value and
13689
                                 detail::has_non_default_from_json<basic_json_t, ValueType>::value,
13690
                                 int> = 0>
13691
    ValueType get() const noexcept(noexcept(
13692
                                       JSONSerializer<ValueTypeCV>::from_json(std::declval<const basic_json_t&>())))
13693
    {
13694
        static_assert(not std::is_reference<ValueTypeCV>::value,
13695
                      "get() cannot be used with reference types, you might want to use get_ref()");
13696
        return JSONSerializer<ValueTypeCV>::from_json(*this);
13697
    }
13698
13699
    /*!
13700
    @brief get a pointer value (explicit)
13701
13702
    Explicit pointer access to the internally stored JSON value. No copies are
13703
    made.
13704
13705
    @warning The pointer becomes invalid if the underlying JSON object
13706
    changes.
13707
13708
    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
13709
    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
13710
    @ref number_unsigned_t, or @ref number_float_t.
13711
13712
    @return pointer to the internally stored JSON value if the requested
13713
    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
13714
13715
    @complexity Constant.
13716
13717
    @liveexample{The example below shows how pointers to internal values of a
13718
    JSON value can be requested. Note that no type conversions are made and a
13719
    `nullptr` is returned if the value and the requested pointer type does not
13720
    match.,get__PointerType}
13721
13722
    @sa @ref get_ptr() for explicit pointer-member access
13723
13724
    @since version 1.0.0
13725
    */
13726
    template<typename PointerType, typename std::enable_if<
13727
                 std::is_pointer<PointerType>::value, int>::type = 0>
13728
    PointerType get() noexcept
13729
    {
13730
        // delegate the call to get_ptr
13731
        return get_ptr<PointerType>();
13732
    }
13733
13734
    /*!
13735
    @brief get a pointer value (explicit)
13736
    @copydoc get()
13737
    */
13738
    template<typename PointerType, typename std::enable_if<
13739
                 std::is_pointer<PointerType>::value, int>::type = 0>
13740
    constexpr const PointerType get() const noexcept
13741
    {
13742
        // delegate the call to get_ptr
13743
        return get_ptr<PointerType>();
13744
    }
13745
13746
    /*!
13747
    @brief get a pointer value (implicit)
13748
13749
    Implicit pointer access to the internally stored JSON value. No copies are
13750
    made.
13751
13752
    @warning Writing data to the pointee of the result yields an undefined
13753
    state.
13754
13755
    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
13756
    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
13757
    @ref number_unsigned_t, or @ref number_float_t. Enforced by a static
13758
    assertion.
13759
13760
    @return pointer to the internally stored JSON value if the requested
13761
    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
13762
13763
    @complexity Constant.
13764
13765
    @liveexample{The example below shows how pointers to internal values of a
13766
    JSON value can be requested. Note that no type conversions are made and a
13767
    `nullptr` is returned if the value and the requested pointer type does not
13768
    match.,get_ptr}
13769
13770
    @since version 1.0.0
13771
    */
13772
    template<typename PointerType, typename std::enable_if<
13773
                 std::is_pointer<PointerType>::value, int>::type = 0>
13774
    PointerType get_ptr() noexcept
13775
    {
13776
        // get the type of the PointerType (remove pointer and const)
13777
        using pointee_t = typename std::remove_const<typename
13778
                          std::remove_pointer<typename
13779
                          std::remove_const<PointerType>::type>::type>::type;
13780
        // make sure the type matches the allowed types
13781
        static_assert(
13782
            std::is_same<object_t, pointee_t>::value
13783
            or std::is_same<array_t, pointee_t>::value
13784
            or std::is_same<string_t, pointee_t>::value
13785
            or std::is_same<boolean_t, pointee_t>::value
13786
            or std::is_same<number_integer_t, pointee_t>::value
13787
            or std::is_same<number_unsigned_t, pointee_t>::value
13788
            or std::is_same<number_float_t, pointee_t>::value
13789
            , "incompatible pointer type");
13790
13791
        // delegate the call to get_impl_ptr<>()
13792
        return get_impl_ptr(static_cast<PointerType>(nullptr));
13793
    }
13794
13795
    /*!
13796
    @brief get a pointer value (implicit)
13797
    @copydoc get_ptr()
13798
    */
13799
    template<typename PointerType, typename std::enable_if<
13800
                 std::is_pointer<PointerType>::value and
13801
                 std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
13802
    constexpr const PointerType get_ptr() const noexcept
13803
47.7k
    {
13804
47.7k
        // get the type of the PointerType (remove pointer and const)
13805
47.7k
        using pointee_t = typename std::remove_const<typename
13806
47.7k
                          std::remove_pointer<typename
13807
47.7k
                          std::remove_const<PointerType>::type>::type>::type;
13808
47.7k
        // make sure the type matches the allowed types
13809
47.7k
        static_assert(
13810
47.7k
            std::is_same<object_t, pointee_t>::value
13811
47.7k
            or std::is_same<array_t, pointee_t>::value
13812
47.7k
            or std::is_same<string_t, pointee_t>::value
13813
47.7k
            or std::is_same<boolean_t, pointee_t>::value
13814
47.7k
            or std::is_same<number_integer_t, pointee_t>::value
13815
47.7k
            or std::is_same<number_unsigned_t, pointee_t>::value
13816
47.7k
            or std::is_same<number_float_t, pointee_t>::value
13817
47.7k
            , "incompatible pointer type");
13818
47.7k
13819
47.7k
        // delegate the call to get_impl_ptr<>() const
13820
47.7k
        return get_impl_ptr(static_cast<PointerType>(nullptr));
13821
47.7k
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE7get_ptrIPKbLi0EEEKT_v
Line
Count
Source
13803
8
    {
13804
8
        // get the type of the PointerType (remove pointer and const)
13805
8
        using pointee_t = typename std::remove_const<typename
13806
8
                          std::remove_pointer<typename
13807
8
                          std::remove_const<PointerType>::type>::type>::type;
13808
8
        // make sure the type matches the allowed types
13809
8
        static_assert(
13810
8
            std::is_same<object_t, pointee_t>::value
13811
8
            or std::is_same<array_t, pointee_t>::value
13812
8
            or std::is_same<string_t, pointee_t>::value
13813
8
            or std::is_same<boolean_t, pointee_t>::value
13814
8
            or std::is_same<number_integer_t, pointee_t>::value
13815
8
            or std::is_same<number_unsigned_t, pointee_t>::value
13816
8
            or std::is_same<number_float_t, pointee_t>::value
13817
8
            , "incompatible pointer type");
13818
8
13819
8
        // delegate the call to get_impl_ptr<>() const
13820
8
        return get_impl_ptr(static_cast<PointerType>(nullptr));
13821
8
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE7get_ptrIPKS8_Li0EEEKT_v
Line
Count
Source
13803
46.5k
    {
13804
46.5k
        // get the type of the PointerType (remove pointer and const)
13805
46.5k
        using pointee_t = typename std::remove_const<typename
13806
46.5k
                          std::remove_pointer<typename
13807
46.5k
                          std::remove_const<PointerType>::type>::type>::type;
13808
46.5k
        // make sure the type matches the allowed types
13809
46.5k
        static_assert(
13810
46.5k
            std::is_same<object_t, pointee_t>::value
13811
46.5k
            or std::is_same<array_t, pointee_t>::value
13812
46.5k
            or std::is_same<string_t, pointee_t>::value
13813
46.5k
            or std::is_same<boolean_t, pointee_t>::value
13814
46.5k
            or std::is_same<number_integer_t, pointee_t>::value
13815
46.5k
            or std::is_same<number_unsigned_t, pointee_t>::value
13816
46.5k
            or std::is_same<number_float_t, pointee_t>::value
13817
46.5k
            , "incompatible pointer type");
13818
46.5k
13819
46.5k
        // delegate the call to get_impl_ptr<>() const
13820
46.5k
        return get_impl_ptr(static_cast<PointerType>(nullptr));
13821
46.5k
    }
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE7get_ptrIPKmLi0EEEKT_v
Line
Count
Source
13803
608
    {
13804
608
        // get the type of the PointerType (remove pointer and const)
13805
608
        using pointee_t = typename std::remove_const<typename
13806
608
                          std::remove_pointer<typename
13807
608
                          std::remove_const<PointerType>::type>::type>::type;
13808
608
        // make sure the type matches the allowed types
13809
608
        static_assert(
13810
608
            std::is_same<object_t, pointee_t>::value
13811
608
            or std::is_same<array_t, pointee_t>::value
13812
608
            or std::is_same<string_t, pointee_t>::value
13813
608
            or std::is_same<boolean_t, pointee_t>::value
13814
608
            or std::is_same<number_integer_t, pointee_t>::value
13815
608
            or std::is_same<number_unsigned_t, pointee_t>::value
13816
608
            or std::is_same<number_float_t, pointee_t>::value
13817
608
            , "incompatible pointer type");
13818
608
13819
608
        // delegate the call to get_impl_ptr<>() const
13820
608
        return get_impl_ptr(static_cast<PointerType>(nullptr));
13821
608
    }
Unexecuted instantiation: _ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE7get_ptrIPKlLi0EEEKT_v
_ZNK8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE7get_ptrIPKdLi0EEEKT_v
Line
Count
Source
13803
592
    {
13804
592
        // get the type of the PointerType (remove pointer and const)
13805
592
        using pointee_t = typename std::remove_const<typename
13806
592
                          std::remove_pointer<typename
13807
592
                          std::remove_const<PointerType>::type>::type>::type;
13808
592
        // make sure the type matches the allowed types
13809
592
        static_assert(
13810
592
            std::is_same<object_t, pointee_t>::value
13811
592
            or std::is_same<array_t, pointee_t>::value
13812
592
            or std::is_same<string_t, pointee_t>::value
13813
592
            or std::is_same<boolean_t, pointee_t>::value
13814
592
            or std::is_same<number_integer_t, pointee_t>::value
13815
592
            or std::is_same<number_unsigned_t, pointee_t>::value
13816
592
            or std::is_same<number_float_t, pointee_t>::value
13817
592
            , "incompatible pointer type");
13818
592
13819
592
        // delegate the call to get_impl_ptr<>() const
13820
592
        return get_impl_ptr(static_cast<PointerType>(nullptr));
13821
592
    }
13822
13823
    /*!
13824
    @brief get a reference value (implicit)
13825
13826
    Implicit reference access to the internally stored JSON value. No copies
13827
    are made.
13828
13829
    @warning Writing data to the referee of the result yields an undefined
13830
    state.
13831
13832
    @tparam ReferenceType reference type; must be a reference to @ref array_t,
13833
    @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or
13834
    @ref number_float_t. Enforced by static assertion.
13835
13836
    @return reference to the internally stored JSON value if the requested
13837
    reference type @a ReferenceType fits to the JSON value; throws
13838
    type_error.303 otherwise
13839
13840
    @throw type_error.303 in case passed type @a ReferenceType is incompatible
13841
    with the stored JSON value; see example below
13842
13843
    @complexity Constant.
13844
13845
    @liveexample{The example shows several calls to `get_ref()`.,get_ref}
13846
13847
    @since version 1.1.0
13848
    */
13849
    template<typename ReferenceType, typename std::enable_if<
13850
                 std::is_reference<ReferenceType>::value, int>::type = 0>
13851
    ReferenceType get_ref()
13852
    {
13853
        // delegate call to get_ref_impl
13854
        return get_ref_impl<ReferenceType>(*this);
13855
    }
13856
13857
    /*!
13858
    @brief get a reference value (implicit)
13859
    @copydoc get_ref()
13860
    */
13861
    template<typename ReferenceType, typename std::enable_if<
13862
                 std::is_reference<ReferenceType>::value and
13863
                 std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>
13864
    ReferenceType get_ref() const
13865
    {
13866
        // delegate call to get_ref_impl
13867
        return get_ref_impl<ReferenceType>(*this);
13868
    }
13869
13870
    /*!
13871
    @brief get a value (implicit)
13872
13873
    Implicit type conversion between the JSON value and a compatible value.
13874
    The call is realized by calling @ref get() const.
13875
13876
    @tparam ValueType non-pointer type compatible to the JSON value, for
13877
    instance `int` for JSON integer numbers, `bool` for JSON booleans, or
13878
    `std::vector` types for JSON arrays. The character type of @ref string_t
13879
    as well as an initializer list of this type is excluded to avoid
13880
    ambiguities as these types implicitly convert to `std::string`.
13881
13882
    @return copy of the JSON value, converted to type @a ValueType
13883
13884
    @throw type_error.302 in case passed type @a ValueType is incompatible
13885
    to the JSON value type (e.g., the JSON value is of type boolean, but a
13886
    string is requested); see example below
13887
13888
    @complexity Linear in the size of the JSON value.
13889
13890
    @liveexample{The example below shows several conversions from JSON values
13891
    to other types. There a few things to note: (1) Floating-point numbers can
13892
    be converted to integers\, (2) A JSON array can be converted to a standard
13893
    `std::vector<short>`\, (3) A JSON object can be converted to C++
13894
    associative containers such as `std::unordered_map<std::string\,
13895
    json>`.,operator__ValueType}
13896
13897
    @since version 1.0.0
13898
    */
13899
    template < typename ValueType, typename std::enable_if <
13900
                   not std::is_pointer<ValueType>::value and
13901
                   not std::is_same<ValueType, detail::json_ref<basic_json>>::value and
13902
                   not std::is_same<ValueType, typename string_t::value_type>::value and
13903
                   not detail::is_basic_json<ValueType>::value
13904
#ifndef _MSC_VER  // fix for issue #167 operator<< ambiguity under VS2015
13905
                   and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
13906
#if defined(JSON_HAS_CPP_17) && defined(_MSC_VER) and _MSC_VER <= 1914
13907
                   and not std::is_same<ValueType, typename std::string_view>::value
13908
#endif
13909
#endif
13910
                   , int >::type = 0 >
13911
    operator ValueType() const
13912
    {
13913
        // delegate the call to get<>() const
13914
        return get<ValueType>();
13915
    }
13916
13917
    /// @}
13918
13919
13920
    ////////////////////
13921
    // element access //
13922
    ////////////////////
13923
13924
    /// @name element access
13925
    /// Access to the JSON value.
13926
    /// @{
13927
13928
    /*!
13929
    @brief access specified array element with bounds checking
13930
13931
    Returns a reference to the element at specified location @a idx, with
13932
    bounds checking.
13933
13934
    @param[in] idx  index of the element to access
13935
13936
    @return reference to the element at index @a idx
13937
13938
    @throw type_error.304 if the JSON value is not an array; in this case,
13939
    calling `at` with an index makes no sense. See example below.
13940
    @throw out_of_range.401 if the index @a idx is out of range of the array;
13941
    that is, `idx >= size()`. See example below.
13942
13943
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
13944
    changes in the JSON value.
13945
13946
    @complexity Constant.
13947
13948
    @since version 1.0.0
13949
13950
    @liveexample{The example below shows how array elements can be read and
13951
    written using `at()`. It also demonstrates the different exceptions that
13952
    can be thrown.,at__size_type}
13953
    */
13954
    reference at(size_type idx)
13955
    {
13956
        // at only works for arrays
13957
        if (JSON_LIKELY(is_array()))
13958
        {
13959
            JSON_TRY
13960
            {
13961
                return m_value.array->at(idx);
13962
            }
13963
            JSON_CATCH (std::out_of_range&)
13964
            {
13965
                // create better exception explanation
13966
                JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
13967
            }
13968
        }
13969
        else
13970
        {
13971
            JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name())));
13972
        }
13973
    }
13974
13975
    /*!
13976
    @brief access specified array element with bounds checking
13977
13978
    Returns a const reference to the element at specified location @a idx,
13979
    with bounds checking.
13980
13981
    @param[in] idx  index of the element to access
13982
13983
    @return const reference to the element at index @a idx
13984
13985
    @throw type_error.304 if the JSON value is not an array; in this case,
13986
    calling `at` with an index makes no sense. See example below.
13987
    @throw out_of_range.401 if the index @a idx is out of range of the array;
13988
    that is, `idx >= size()`. See example below.
13989
13990
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
13991
    changes in the JSON value.
13992
13993
    @complexity Constant.
13994
13995
    @since version 1.0.0
13996
13997
    @liveexample{The example below shows how array elements can be read using
13998
    `at()`. It also demonstrates the different exceptions that can be thrown.,
13999
    at__size_type_const}
14000
    */
14001
    const_reference at(size_type idx) const
14002
    {
14003
        // at only works for arrays
14004
        if (JSON_LIKELY(is_array()))
14005
        {
14006
            JSON_TRY
14007
            {
14008
                return m_value.array->at(idx);
14009
            }
14010
            JSON_CATCH (std::out_of_range&)
14011
            {
14012
                // create better exception explanation
14013
                JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
14014
            }
14015
        }
14016
        else
14017
        {
14018
            JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name())));
14019
        }
14020
    }
14021
14022
    /*!
14023
    @brief access specified object element with bounds checking
14024
14025
    Returns a reference to the element at with specified key @a key, with
14026
    bounds checking.
14027
14028
    @param[in] key  key of the element to access
14029
14030
    @return reference to the element at key @a key
14031
14032
    @throw type_error.304 if the JSON value is not an object; in this case,
14033
    calling `at` with a key makes no sense. See example below.
14034
    @throw out_of_range.403 if the key @a key is is not stored in the object;
14035
    that is, `find(key) == end()`. See example below.
14036
14037
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
14038
    changes in the JSON value.
14039
14040
    @complexity Logarithmic in the size of the container.
14041
14042
    @sa @ref operator[](const typename object_t::key_type&) for unchecked
14043
    access by reference
14044
    @sa @ref value() for access by value with a default value
14045
14046
    @since version 1.0.0
14047
14048
    @liveexample{The example below shows how object elements can be read and
14049
    written using `at()`. It also demonstrates the different exceptions that
14050
    can be thrown.,at__object_t_key_type}
14051
    */
14052
    reference at(const typename object_t::key_type& key)
14053
51.3k
    {
14054
51.3k
        // at only works for objects
14055
51.3k
        if (JSON_LIKELY(is_object()))
14056
51.3k
        {
14057
51.3k
            JSON_TRY
14058
51.3k
            {
14059
51.3k
                return m_value.object->at(key);
14060
51.3k
            }
14061
4
            JSON_CATCH (std::out_of_range&)
14062
4
            {
14063
4
                // create better exception explanation
14064
4
                JSON_THROW(out_of_range::create(403, "key '" + key + "' not found"));
14065
4
            }
14066
0
        }
14067
0
        else
14068
0
        {
14069
0
            JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name())));
14070
0
        }
14071
0
    }
14072
14073
    /*!
14074
    @brief access specified object element with bounds checking
14075
14076
    Returns a const reference to the element at with specified key @a key,
14077
    with bounds checking.
14078
14079
    @param[in] key  key of the element to access
14080
14081
    @return const reference to the element at key @a key
14082
14083
    @throw type_error.304 if the JSON value is not an object; in this case,
14084
    calling `at` with a key makes no sense. See example below.
14085
    @throw out_of_range.403 if the key @a key is is not stored in the object;
14086
    that is, `find(key) == end()`. See example below.
14087
14088
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
14089
    changes in the JSON value.
14090
14091
    @complexity Logarithmic in the size of the container.
14092
14093
    @sa @ref operator[](const typename object_t::key_type&) for unchecked
14094
    access by reference
14095
    @sa @ref value() for access by value with a default value
14096
14097
    @since version 1.0.0
14098
14099
    @liveexample{The example below shows how object elements can be read using
14100
    `at()`. It also demonstrates the different exceptions that can be thrown.,
14101
    at__object_t_key_type_const}
14102
    */
14103
    const_reference at(const typename object_t::key_type& key) const
14104
    {
14105
        // at only works for objects
14106
        if (JSON_LIKELY(is_object()))
14107
        {
14108
            JSON_TRY
14109
            {
14110
                return m_value.object->at(key);
14111
            }
14112
            JSON_CATCH (std::out_of_range&)
14113
            {
14114
                // create better exception explanation
14115
                JSON_THROW(out_of_range::create(403, "key '" + key + "' not found"));
14116
            }
14117
        }
14118
        else
14119
        {
14120
            JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name())));
14121
        }
14122
    }
14123
14124
    /*!
14125
    @brief access specified array element
14126
14127
    Returns a reference to the element at specified location @a idx.
14128
14129
    @note If @a idx is beyond the range of the array (i.e., `idx >= size()`),
14130
    then the array is silently filled up with `null` values to make `idx` a
14131
    valid reference to the last stored element.
14132
14133
    @param[in] idx  index of the element to access
14134
14135
    @return reference to the element at index @a idx
14136
14137
    @throw type_error.305 if the JSON value is not an array or null; in that
14138
    cases, using the [] operator with an index makes no sense.
14139
14140
    @complexity Constant if @a idx is in the range of the array. Otherwise
14141
    linear in `idx - size()`.
14142
14143
    @liveexample{The example below shows how array elements can be read and
14144
    written using `[]` operator. Note the addition of `null`
14145
    values.,operatorarray__size_type}
14146
14147
    @since version 1.0.0
14148
    */
14149
    reference operator[](size_type idx)
14150
    {
14151
        // implicitly convert null value to an empty array
14152
        if (is_null())
14153
        {
14154
            m_type = value_t::array;
14155
            m_value.array = create<array_t>();
14156
            assert_invariant();
14157
        }
14158
14159
        // operator[] only works for arrays
14160
        if (JSON_LIKELY(is_array()))
14161
        {
14162
            // fill up array with null values if given idx is outside range
14163
            if (idx >= m_value.array->size())
14164
            {
14165
                m_value.array->insert(m_value.array->end(),
14166
                                      idx - m_value.array->size() + 1,
14167
                                      basic_json());
14168
            }
14169
14170
            return m_value.array->operator[](idx);
14171
        }
14172
14173
        JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name())));
14174
    }
14175
14176
    /*!
14177
    @brief access specified array element
14178
14179
    Returns a const reference to the element at specified location @a idx.
14180
14181
    @param[in] idx  index of the element to access
14182
14183
    @return const reference to the element at index @a idx
14184
14185
    @throw type_error.305 if the JSON value is not an array; in that case,
14186
    using the [] operator with an index makes no sense.
14187
14188
    @complexity Constant.
14189
14190
    @liveexample{The example below shows how array elements can be read using
14191
    the `[]` operator.,operatorarray__size_type_const}
14192
14193
    @since version 1.0.0
14194
    */
14195
    const_reference operator[](size_type idx) const
14196
    {
14197
        // const operator[] only works for arrays
14198
        if (JSON_LIKELY(is_array()))
14199
        {
14200
            return m_value.array->operator[](idx);
14201
        }
14202
14203
        JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name())));
14204
    }
14205
14206
    /*!
14207
    @brief access specified object element
14208
14209
    Returns a reference to the element at with specified key @a key.
14210
14211
    @note If @a key is not found in the object, then it is silently added to
14212
    the object and filled with a `null` value to make `key` a valid reference.
14213
    In case the value was `null` before, it is converted to an object.
14214
14215
    @param[in] key  key of the element to access
14216
14217
    @return reference to the element at key @a key
14218
14219
    @throw type_error.305 if the JSON value is not an object or null; in that
14220
    cases, using the [] operator with a key makes no sense.
14221
14222
    @complexity Logarithmic in the size of the container.
14223
14224
    @liveexample{The example below shows how object elements can be read and
14225
    written using the `[]` operator.,operatorarray__key_type}
14226
14227
    @sa @ref at(const typename object_t::key_type&) for access by reference
14228
    with range checking
14229
    @sa @ref value() for access by value with a default value
14230
14231
    @since version 1.0.0
14232
    */
14233
    reference operator[](const typename object_t::key_type& key)
14234
1.26k
    {
14235
1.26k
        // implicitly convert null value to an empty object
14236
1.26k
        if (is_null())
14237
316
        {
14238
316
            m_type = value_t::object;
14239
316
            m_value.object = create<object_t>();
14240
316
            assert_invariant();
14241
316
        }
14242
1.26k
14243
1.26k
        // operator[] only works for objects
14244
1.26k
        if (JSON_LIKELY(is_object()))
14245
1.26k
        {
14246
1.26k
            return m_value.object->operator[](key);
14247
1.26k
        }
14248
0
14249
0
        JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
14250
0
    }
14251
14252
    /*!
14253
    @brief read-only access specified object element
14254
14255
    Returns a const reference to the element at with specified key @a key. No
14256
    bounds checking is performed.
14257
14258
    @warning If the element with key @a key does not exist, the behavior is
14259
    undefined.
14260
14261
    @param[in] key  key of the element to access
14262
14263
    @return const reference to the element at key @a key
14264
14265
    @pre The element with key @a key must exist. **This precondition is
14266
         enforced with an assertion.**
14267
14268
    @throw type_error.305 if the JSON value is not an object; in that case,
14269
    using the [] operator with a key makes no sense.
14270
14271
    @complexity Logarithmic in the size of the container.
14272
14273
    @liveexample{The example below shows how object elements can be read using
14274
    the `[]` operator.,operatorarray__key_type_const}
14275
14276
    @sa @ref at(const typename object_t::key_type&) for access by reference
14277
    with range checking
14278
    @sa @ref value() for access by value with a default value
14279
14280
    @since version 1.0.0
14281
    */
14282
    const_reference operator[](const typename object_t::key_type& key) const
14283
    {
14284
        // const operator[] only works for objects
14285
        if (JSON_LIKELY(is_object()))
14286
        {
14287
            assert(m_value.object->find(key) != m_value.object->end());
14288
            return m_value.object->find(key)->second;
14289
        }
14290
14291
        JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
14292
    }
14293
14294
    /*!
14295
    @brief access specified object element
14296
14297
    Returns a reference to the element at with specified key @a key.
14298
14299
    @note If @a key is not found in the object, then it is silently added to
14300
    the object and filled with a `null` value to make `key` a valid reference.
14301
    In case the value was `null` before, it is converted to an object.
14302
14303
    @param[in] key  key of the element to access
14304
14305
    @return reference to the element at key @a key
14306
14307
    @throw type_error.305 if the JSON value is not an object or null; in that
14308
    cases, using the [] operator with a key makes no sense.
14309
14310
    @complexity Logarithmic in the size of the container.
14311
14312
    @liveexample{The example below shows how object elements can be read and
14313
    written using the `[]` operator.,operatorarray__key_type}
14314
14315
    @sa @ref at(const typename object_t::key_type&) for access by reference
14316
    with range checking
14317
    @sa @ref value() for access by value with a default value
14318
14319
    @since version 1.1.0
14320
    */
14321
    template<typename T>
14322
    reference operator[](T* key)
14323
5.37k
    {
14324
5.37k
        // implicitly convert null to object
14325
5.37k
        if (is_null())
14326
1.10k
        {
14327
1.10k
            m_type = value_t::object;
14328
1.10k
            m_value = value_t::object;
14329
1.10k
            assert_invariant();
14330
1.10k
        }
14331
5.37k
14332
5.37k
        // at only works for objects
14333
5.37k
        if (JSON_LIKELY(is_object()))
14334
5.37k
        {
14335
5.37k
            return m_value.object->operator[](key);
14336
5.37k
        }
14337
0
14338
0
        JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
14339
0
    }
14340
14341
    /*!
14342
    @brief read-only access specified object element
14343
14344
    Returns a const reference to the element at with specified key @a key. No
14345
    bounds checking is performed.
14346
14347
    @warning If the element with key @a key does not exist, the behavior is
14348
    undefined.
14349
14350
    @param[in] key  key of the element to access
14351
14352
    @return const reference to the element at key @a key
14353
14354
    @pre The element with key @a key must exist. **This precondition is
14355
         enforced with an assertion.**
14356
14357
    @throw type_error.305 if the JSON value is not an object; in that case,
14358
    using the [] operator with a key makes no sense.
14359
14360
    @complexity Logarithmic in the size of the container.
14361
14362
    @liveexample{The example below shows how object elements can be read using
14363
    the `[]` operator.,operatorarray__key_type_const}
14364
14365
    @sa @ref at(const typename object_t::key_type&) for access by reference
14366
    with range checking
14367
    @sa @ref value() for access by value with a default value
14368
14369
    @since version 1.1.0
14370
    */
14371
    template<typename T>
14372
    const_reference operator[](T* key) const
14373
    {
14374
        // at only works for objects
14375
        if (JSON_LIKELY(is_object()))
14376
        {
14377
            assert(m_value.object->find(key) != m_value.object->end());
14378
            return m_value.object->find(key)->second;
14379
        }
14380
14381
        JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
14382
    }
14383
14384
    /*!
14385
    @brief access specified object element with default value
14386
14387
    Returns either a copy of an object's element at the specified key @a key
14388
    or a given default value if no element with key @a key exists.
14389
14390
    The function is basically equivalent to executing
14391
    @code {.cpp}
14392
    try {
14393
        return at(key);
14394
    } catch(out_of_range) {
14395
        return default_value;
14396
    }
14397
    @endcode
14398
14399
    @note Unlike @ref at(const typename object_t::key_type&), this function
14400
    does not throw if the given key @a key was not found.
14401
14402
    @note Unlike @ref operator[](const typename object_t::key_type& key), this
14403
    function does not implicitly add an element to the position defined by @a
14404
    key. This function is furthermore also applicable to const objects.
14405
14406
    @param[in] key  key of the element to access
14407
    @param[in] default_value  the value to return if @a key is not found
14408
14409
    @tparam ValueType type compatible to JSON values, for instance `int` for
14410
    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
14411
    JSON arrays. Note the type of the expected value at @a key and the default
14412
    value @a default_value must be compatible.
14413
14414
    @return copy of the element at key @a key or @a default_value if @a key
14415
    is not found
14416
14417
    @throw type_error.306 if the JSON value is not an object; in that case,
14418
    using `value()` with a key makes no sense.
14419
14420
    @complexity Logarithmic in the size of the container.
14421
14422
    @liveexample{The example below shows how object elements can be queried
14423
    with a default value.,basic_json__value}
14424
14425
    @sa @ref at(const typename object_t::key_type&) for access by reference
14426
    with range checking
14427
    @sa @ref operator[](const typename object_t::key_type&) for unchecked
14428
    access by reference
14429
14430
    @since version 1.0.0
14431
    */
14432
    template<class ValueType, typename std::enable_if<
14433
                 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
14434
    ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
14435
    {
14436
        // at only works for objects
14437
        if (JSON_LIKELY(is_object()))
14438
        {
14439
            // if key is found, return value and given default value otherwise
14440
            const auto it = find(key);
14441
            if (it != end())
14442
            {
14443
                return *it;
14444
            }
14445
14446
            return default_value;
14447
        }
14448
14449
        JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name())));
14450
    }
14451
14452
    /*!
14453
    @brief overload for a default value of type const char*
14454
    @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const
14455
    */
14456
    string_t value(const typename object_t::key_type& key, const char* default_value) const
14457
    {
14458
        return value(key, string_t(default_value));
14459
    }
14460
14461
    /*!
14462
    @brief access specified object element via JSON Pointer with default value
14463
14464
    Returns either a copy of an object's element at the specified key @a key
14465
    or a given default value if no element with key @a key exists.
14466
14467
    The function is basically equivalent to executing
14468
    @code {.cpp}
14469
    try {
14470
        return at(ptr);
14471
    } catch(out_of_range) {
14472
        return default_value;
14473
    }
14474
    @endcode
14475
14476
    @note Unlike @ref at(const json_pointer&), this function does not throw
14477
    if the given key @a key was not found.
14478
14479
    @param[in] ptr  a JSON pointer to the element to access
14480
    @param[in] default_value  the value to return if @a ptr found no value
14481
14482
    @tparam ValueType type compatible to JSON values, for instance `int` for
14483
    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
14484
    JSON arrays. Note the type of the expected value at @a key and the default
14485
    value @a default_value must be compatible.
14486
14487
    @return copy of the element at key @a key or @a default_value if @a key
14488
    is not found
14489
14490
    @throw type_error.306 if the JSON value is not an object; in that case,
14491
    using `value()` with a key makes no sense.
14492
14493
    @complexity Logarithmic in the size of the container.
14494
14495
    @liveexample{The example below shows how object elements can be queried
14496
    with a default value.,basic_json__value_ptr}
14497
14498
    @sa @ref operator[](const json_pointer&) for unchecked access by reference
14499
14500
    @since version 2.0.2
14501
    */
14502
    template<class ValueType, typename std::enable_if<
14503
                 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
14504
    ValueType value(const json_pointer& ptr, const ValueType& default_value) const
14505
    {
14506
        // at only works for objects
14507
        if (JSON_LIKELY(is_object()))
14508
        {
14509
            // if pointer resolves a value, return it or use default value
14510
            JSON_TRY
14511
            {
14512
                return ptr.get_checked(this);
14513
            }
14514
            JSON_INTERNAL_CATCH (out_of_range&)
14515
            {
14516
                return default_value;
14517
            }
14518
        }
14519
14520
        JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name())));
14521
    }
14522
14523
    /*!
14524
    @brief overload for a default value of type const char*
14525
    @copydoc basic_json::value(const json_pointer&, ValueType) const
14526
    */
14527
    string_t value(const json_pointer& ptr, const char* default_value) const
14528
    {
14529
        return value(ptr, string_t(default_value));
14530
    }
14531
14532
    /*!
14533
    @brief access the first element
14534
14535
    Returns a reference to the first element in the container. For a JSON
14536
    container `c`, the expression `c.front()` is equivalent to `*c.begin()`.
14537
14538
    @return In case of a structured type (array or object), a reference to the
14539
    first element is returned. In case of number, string, or boolean values, a
14540
    reference to the value is returned.
14541
14542
    @complexity Constant.
14543
14544
    @pre The JSON value must not be `null` (would throw `std::out_of_range`)
14545
    or an empty array or object (undefined behavior, **guarded by
14546
    assertions**).
14547
    @post The JSON value remains unchanged.
14548
14549
    @throw invalid_iterator.214 when called on `null` value
14550
14551
    @liveexample{The following code shows an example for `front()`.,front}
14552
14553
    @sa @ref back() -- access the last element
14554
14555
    @since version 1.0.0
14556
    */
14557
    reference front()
14558
    {
14559
        return *begin();
14560
    }
14561
14562
    /*!
14563
    @copydoc basic_json::front()
14564
    */
14565
    const_reference front() const
14566
    {
14567
        return *cbegin();
14568
    }
14569
14570
    /*!
14571
    @brief access the last element
14572
14573
    Returns a reference to the last element in the container. For a JSON
14574
    container `c`, the expression `c.back()` is equivalent to
14575
    @code {.cpp}
14576
    auto tmp = c.end();
14577
    --tmp;
14578
    return *tmp;
14579
    @endcode
14580
14581
    @return In case of a structured type (array or object), a reference to the
14582
    last element is returned. In case of number, string, or boolean values, a
14583
    reference to the value is returned.
14584
14585
    @complexity Constant.
14586
14587
    @pre The JSON value must not be `null` (would throw `std::out_of_range`)
14588
    or an empty array or object (undefined behavior, **guarded by
14589
    assertions**).
14590
    @post The JSON value remains unchanged.
14591
14592
    @throw invalid_iterator.214 when called on a `null` value. See example
14593
    below.
14594
14595
    @liveexample{The following code shows an example for `back()`.,back}
14596
14597
    @sa @ref front() -- access the first element
14598
14599
    @since version 1.0.0
14600
    */
14601
    reference back()
14602
    {
14603
        auto tmp = end();
14604
        --tmp;
14605
        return *tmp;
14606
    }
14607
14608
    /*!
14609
    @copydoc basic_json::back()
14610
    */
14611
    const_reference back() const
14612
    {
14613
        auto tmp = cend();
14614
        --tmp;
14615
        return *tmp;
14616
    }
14617
14618
    /*!
14619
    @brief remove element given an iterator
14620
14621
    Removes the element specified by iterator @a pos. The iterator @a pos must
14622
    be valid and dereferenceable. Thus the `end()` iterator (which is valid,
14623
    but is not dereferenceable) cannot be used as a value for @a pos.
14624
14625
    If called on a primitive type other than `null`, the resulting JSON value
14626
    will be `null`.
14627
14628
    @param[in] pos iterator to the element to remove
14629
    @return Iterator following the last removed element. If the iterator @a
14630
    pos refers to the last element, the `end()` iterator is returned.
14631
14632
    @tparam IteratorType an @ref iterator or @ref const_iterator
14633
14634
    @post Invalidates iterators and references at or after the point of the
14635
    erase, including the `end()` iterator.
14636
14637
    @throw type_error.307 if called on a `null` value; example: `"cannot use
14638
    erase() with null"`
14639
    @throw invalid_iterator.202 if called on an iterator which does not belong
14640
    to the current JSON value; example: `"iterator does not fit current
14641
    value"`
14642
    @throw invalid_iterator.205 if called on a primitive type with invalid
14643
    iterator (i.e., any iterator which is not `begin()`); example: `"iterator
14644
    out of range"`
14645
14646
    @complexity The complexity depends on the type:
14647
    - objects: amortized constant
14648
    - arrays: linear in distance between @a pos and the end of the container
14649
    - strings: linear in the length of the string
14650
    - other types: constant
14651
14652
    @liveexample{The example shows the result of `erase()` for different JSON
14653
    types.,erase__IteratorType}
14654
14655
    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
14656
    the given range
14657
    @sa @ref erase(const typename object_t::key_type&) -- removes the element
14658
    from an object at the given key
14659
    @sa @ref erase(const size_type) -- removes the element from an array at
14660
    the given index
14661
14662
    @since version 1.0.0
14663
    */
14664
    template<class IteratorType, typename std::enable_if<
14665
                 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
14666
                 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
14667
             = 0>
14668
    IteratorType erase(IteratorType pos)
14669
0
    {
14670
0
        // make sure iterator fits the current value
14671
0
        if (JSON_UNLIKELY(this != pos.m_object))
14672
0
        {
14673
0
            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
14674
0
        }
14675
0
14676
0
        IteratorType result = end();
14677
0
14678
0
        switch (m_type)
14679
0
        {
14680
0
            case value_t::boolean:
14681
0
            case value_t::number_float:
14682
0
            case value_t::number_integer:
14683
0
            case value_t::number_unsigned:
14684
0
            case value_t::string:
14685
0
            {
14686
0
                if (JSON_UNLIKELY(not pos.m_it.primitive_iterator.is_begin()))
14687
0
                {
14688
0
                    JSON_THROW(invalid_iterator::create(205, "iterator out of range"));
14689
0
                }
14690
0
14691
0
                if (is_string())
14692
0
                {
14693
0
                    AllocatorType<string_t> alloc;
14694
0
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);
14695
0
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
14696
0
                    m_value.string = nullptr;
14697
0
                }
14698
0
14699
0
                m_type = value_t::null;
14700
0
                assert_invariant();
14701
0
                break;
14702
0
            }
14703
0
14704
0
            case value_t::object:
14705
0
            {
14706
0
                result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
14707
0
                break;
14708
0
            }
14709
0
14710
0
            case value_t::array:
14711
0
            {
14712
0
                result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
14713
0
                break;
14714
0
            }
14715
0
14716
0
            default:
14717
0
                JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name())));
14718
0
        }
14719
0
14720
0
        return result;
14721
0
    }
14722
14723
    /*!
14724
    @brief remove elements given an iterator range
14725
14726
    Removes the element specified by the range `[first; last)`. The iterator
14727
    @a first does not need to be dereferenceable if `first == last`: erasing
14728
    an empty range is a no-op.
14729
14730
    If called on a primitive type other than `null`, the resulting JSON value
14731
    will be `null`.
14732
14733
    @param[in] first iterator to the beginning of the range to remove
14734
    @param[in] last iterator past the end of the range to remove
14735
    @return Iterator following the last removed element. If the iterator @a
14736
    second refers to the last element, the `end()` iterator is returned.
14737
14738
    @tparam IteratorType an @ref iterator or @ref const_iterator
14739
14740
    @post Invalidates iterators and references at or after the point of the
14741
    erase, including the `end()` iterator.
14742
14743
    @throw type_error.307 if called on a `null` value; example: `"cannot use
14744
    erase() with null"`
14745
    @throw invalid_iterator.203 if called on iterators which does not belong
14746
    to the current JSON value; example: `"iterators do not fit current value"`
14747
    @throw invalid_iterator.204 if called on a primitive type with invalid
14748
    iterators (i.e., if `first != begin()` and `last != end()`); example:
14749
    `"iterators out of range"`
14750
14751
    @complexity The complexity depends on the type:
14752
    - objects: `log(size()) + std::distance(first, last)`
14753
    - arrays: linear in the distance between @a first and @a last, plus linear
14754
      in the distance between @a last and end of the container
14755
    - strings: linear in the length of the string
14756
    - other types: constant
14757
14758
    @liveexample{The example shows the result of `erase()` for different JSON
14759
    types.,erase__IteratorType_IteratorType}
14760
14761
    @sa @ref erase(IteratorType) -- removes the element at a given position
14762
    @sa @ref erase(const typename object_t::key_type&) -- removes the element
14763
    from an object at the given key
14764
    @sa @ref erase(const size_type) -- removes the element from an array at
14765
    the given index
14766
14767
    @since version 1.0.0
14768
    */
14769
    template<class IteratorType, typename std::enable_if<
14770
                 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
14771
                 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
14772
             = 0>
14773
    IteratorType erase(IteratorType first, IteratorType last)
14774
    {
14775
        // make sure iterator fits the current value
14776
        if (JSON_UNLIKELY(this != first.m_object or this != last.m_object))
14777
        {
14778
            JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value"));
14779
        }
14780
14781
        IteratorType result = end();
14782
14783
        switch (m_type)
14784
        {
14785
            case value_t::boolean:
14786
            case value_t::number_float:
14787
            case value_t::number_integer:
14788
            case value_t::number_unsigned:
14789
            case value_t::string:
14790
            {
14791
                if (JSON_LIKELY(not first.m_it.primitive_iterator.is_begin()
14792
                                or not last.m_it.primitive_iterator.is_end()))
14793
                {
14794
                    JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
14795
                }
14796
14797
                if (is_string())
14798
                {
14799
                    AllocatorType<string_t> alloc;
14800
                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);
14801
                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
14802
                    m_value.string = nullptr;
14803
                }
14804
14805
                m_type = value_t::null;
14806
                assert_invariant();
14807
                break;
14808
            }
14809
14810
            case value_t::object:
14811
            {
14812
                result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
14813
                                              last.m_it.object_iterator);
14814
                break;
14815
            }
14816
14817
            case value_t::array:
14818
            {
14819
                result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
14820
                                             last.m_it.array_iterator);
14821
                break;
14822
            }
14823
14824
            default:
14825
                JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name())));
14826
        }
14827
14828
        return result;
14829
    }
14830
14831
    /*!
14832
    @brief remove element from a JSON object given a key
14833
14834
    Removes elements from a JSON object with the key value @a key.
14835
14836
    @param[in] key value of the elements to remove
14837
14838
    @return Number of elements removed. If @a ObjectType is the default
14839
    `std::map` type, the return value will always be `0` (@a key was not
14840
    found) or `1` (@a key was found).
14841
14842
    @post References and iterators to the erased elements are invalidated.
14843
    Other references and iterators are not affected.
14844
14845
    @throw type_error.307 when called on a type other than JSON object;
14846
    example: `"cannot use erase() with null"`
14847
14848
    @complexity `log(size()) + count(key)`
14849
14850
    @liveexample{The example shows the effect of `erase()`.,erase__key_type}
14851
14852
    @sa @ref erase(IteratorType) -- removes the element at a given position
14853
    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
14854
    the given range
14855
    @sa @ref erase(const size_type) -- removes the element from an array at
14856
    the given index
14857
14858
    @since version 1.0.0
14859
    */
14860
    size_type erase(const typename object_t::key_type& key)
14861
    {
14862
        // this erase only works for objects
14863
        if (JSON_LIKELY(is_object()))
14864
        {
14865
            return m_value.object->erase(key);
14866
        }
14867
14868
        JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name())));
14869
    }
14870
14871
    /*!
14872
    @brief remove element from a JSON array given an index
14873
14874
    Removes element from a JSON array at the index @a idx.
14875
14876
    @param[in] idx index of the element to remove
14877
14878
    @throw type_error.307 when called on a type other than JSON object;
14879
    example: `"cannot use erase() with null"`
14880
    @throw out_of_range.401 when `idx >= size()`; example: `"array index 17
14881
    is out of range"`
14882
14883
    @complexity Linear in distance between @a idx and the end of the container.
14884
14885
    @liveexample{The example shows the effect of `erase()`.,erase__size_type}
14886
14887
    @sa @ref erase(IteratorType) -- removes the element at a given position
14888
    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
14889
    the given range
14890
    @sa @ref erase(const typename object_t::key_type&) -- removes the element
14891
    from an object at the given key
14892
14893
    @since version 1.0.0
14894
    */
14895
    void erase(const size_type idx)
14896
    {
14897
        // this erase only works for arrays
14898
        if (JSON_LIKELY(is_array()))
14899
        {
14900
            if (JSON_UNLIKELY(idx >= size()))
14901
            {
14902
                JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
14903
            }
14904
14905
            m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
14906
        }
14907
        else
14908
        {
14909
            JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name())));
14910
        }
14911
    }
14912
14913
    /// @}
14914
14915
14916
    ////////////
14917
    // lookup //
14918
    ////////////
14919
14920
    /// @name lookup
14921
    /// @{
14922
14923
    /*!
14924
    @brief find an element in a JSON object
14925
14926
    Finds an element in a JSON object with key equivalent to @a key. If the
14927
    element is not found or the JSON value is not an object, end() is
14928
    returned.
14929
14930
    @note This method always returns @ref end() when executed on a JSON type
14931
          that is not an object.
14932
14933
    @param[in] key key value of the element to search for.
14934
14935
    @return Iterator to an element with key equivalent to @a key. If no such
14936
    element is found or the JSON value is not an object, past-the-end (see
14937
    @ref end()) iterator is returned.
14938
14939
    @complexity Logarithmic in the size of the JSON object.
14940
14941
    @liveexample{The example shows how `find()` is used.,find__key_type}
14942
14943
    @since version 1.0.0
14944
    */
14945
    template<typename KeyT>
14946
    iterator find(KeyT&& key)
14947
60
    {
14948
60
        auto result = end();
14949
60
14950
60
        if (is_object())
14951
56
        {
14952
56
            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));
14953
56
        }
14954
60
14955
60
        return result;
14956
60
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE4findIRA15_KcEENS_6detail9iter_implISA_EEOT_
Line
Count
Source
14947
8
    {
14948
8
        auto result = end();
14949
8
14950
8
        if (is_object())
14951
8
        {
14952
8
            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));
14953
8
        }
14954
8
14955
8
        return result;
14956
8
    }
_ZN8nlohmann10basic_jsonISt3mapSt6vectorNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEblmdSaNS_14adl_serializerEE4findIRA9_KcEENS_6detail9iter_implISA_EEOT_
Line
Count
Source
14947
52
    {
14948
52
        auto result = end();
14949
52
14950
52
        if (is_object())
14951
48
        {
14952
48
            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));
14953
48
        }
14954
52
14955
52
        return result;
14956
52
    }
14957
14958
    /*!
14959
    @brief find an element in a JSON object
14960
    @copydoc find(KeyT&&)
14961
    */
14962
    template<typename KeyT>
14963
    const_iterator find(KeyT&& key) const
14964
    {
14965
        auto result = cend();
14966
14967
        if (is_object())
14968
        {
14969
            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));
14970
        }
14971
14972
        return result;
14973
    }
14974
14975
    /*!
14976
    @brief returns the number of occurrences of a key in a JSON object
14977
14978
    Returns the number of elements with key @a key. If ObjectType is the
14979
    default `std::map` type, the return value will always be `0` (@a key was
14980
    not found) or `1` (@a key was found).
14981
14982
    @note This method always returns `0` when executed on a JSON type that is
14983
          not an object.
14984
14985
    @param[in] key key value of the element to count
14986
14987
    @return Number of elements with key @a key. If the JSON value is not an
14988
    object, the return value will be `0`.
14989
14990
    @complexity Logarithmic in the size of the JSON object.
14991
14992
    @liveexample{The example shows how `count()` is used.,count}
14993
14994
    @since version 1.0.0
14995
    */
14996
    template<typename KeyT>
14997
    size_type count(KeyT&& key) const
14998
    {
14999
        // return 0 for all nonobject types
15000
        return is_object() ? m_value.object->count(std::forward<KeyT>(key)) : 0;
15001
    }
15002
15003
    /// @}
15004
15005
15006
    ///////////////
15007
    // iterators //
15008
    ///////////////
15009
15010
    /// @name iterators
15011
    /// @{
15012
15013
    /*!
15014
    @brief returns an iterator to the first element
15015
15016
    Returns an iterator to the first element.
15017
15018
    @image html range-begin-end.svg "Illustration from cppreference.com"
15019
15020
    @return iterator to the first element
15021
15022
    @complexity Constant.
15023
15024
    @requirement This function helps `basic_json` satisfying the
15025
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
15026
    requirements:
15027
    - The complexity is constant.
15028
15029
    @liveexample{The following code shows an example for `begin()`.,begin}
15030
15031
    @sa @ref cbegin() -- returns a const iterator to the beginning
15032
    @sa @ref end() -- returns an iterator to the end
15033
    @sa @ref cend() -- returns a const iterator to the end
15034
15035
    @since version 1.0.0
15036
    */
15037
    iterator begin() noexcept
15038
2.40k
    {
15039
2.40k
        iterator result(this);
15040
2.40k
        result.set_begin();
15041
2.40k
        return result;
15042
2.40k
    }
15043
15044
    /*!
15045
    @copydoc basic_json::cbegin()
15046
    */
15047
    const_iterator begin() const noexcept
15048
    {
15049
        return cbegin();
15050
    }
15051
15052
    /*!
15053
    @brief returns a const iterator to the first element
15054
15055
    Returns a const iterator to the first element.
15056
15057
    @image html range-begin-end.svg "Illustration from cppreference.com"
15058
15059
    @return const iterator to the first element
15060
15061
    @complexity Constant.
15062
15063
    @requirement This function helps `basic_json` satisfying the
15064
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
15065
    requirements:
15066
    - The complexity is constant.
15067
    - Has the semantics of `const_cast<const basic_json&>(*this).begin()`.
15068
15069
    @liveexample{The following code shows an example for `cbegin()`.,cbegin}
15070
15071
    @sa @ref begin() -- returns an iterator to the beginning
15072
    @sa @ref end() -- returns an iterator to the end
15073
    @sa @ref cend() -- returns a const iterator to the end
15074
15075
    @since version 1.0.0
15076
    */
15077
    const_iterator cbegin() const noexcept
15078
    {
15079
        const_iterator result(this);
15080
        result.set_begin();
15081
        return result;
15082
    }
15083
15084
    /*!
15085
    @brief returns an iterator to one past the last element
15086
15087
    Returns an iterator to one past the last element.
15088
15089
    @image html range-begin-end.svg "Illustration from cppreference.com"
15090
15091
    @return iterator one past the last element
15092
15093
    @complexity Constant.
15094
15095
    @requirement This function helps `basic_json` satisfying the
15096
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
15097
    requirements:
15098
    - The complexity is constant.
15099
15100
    @liveexample{The following code shows an example for `end()`.,end}
15101
15102
    @sa @ref cend() -- returns a const iterator to the end
15103
    @sa @ref begin() -- returns an iterator to the beginning
15104
    @sa @ref cbegin() -- returns a const iterator to the beginning
15105
15106
    @since version 1.0.0
15107
    */
15108
    iterator end() noexcept
15109
8.08k
    {
15110
8.08k
        iterator result(this);
15111
8.08k
        result.set_end();
15112
8.08k
        return result;
15113
8.08k
    }
15114
15115
    /*!
15116
    @copydoc basic_json::cend()
15117
    */
15118
    const_iterator end() const noexcept
15119
    {
15120
        return cend();
15121
    }
15122
15123
    /*!
15124
    @brief returns a const iterator to one past the last element
15125
15126
    Returns a const iterator to one past the last element.
15127
15128
    @image html range-begin-end.svg "Illustration from cppreference.com"
15129
15130
    @return const iterator one past the last element
15131
15132
    @complexity Constant.
15133
15134
    @requirement This function helps `basic_json` satisfying the
15135
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
15136
    requirements:
15137
    - The complexity is constant.
15138
    - Has the semantics of `const_cast<const basic_json&>(*this).end()`.
15139
15140
    @liveexample{The following code shows an example for `cend()`.,cend}
15141
15142
    @sa @ref end() -- returns an iterator to the end
15143
    @sa @ref begin() -- returns an iterator to the beginning
15144
    @sa @ref cbegin() -- returns a const iterator to the beginning
15145
15146
    @since version 1.0.0
15147
    */
15148
    const_iterator cend() const noexcept
15149
    {
15150
        const_iterator result(this);
15151
        result.set_end();
15152
        return result;
15153
    }
15154
15155
    /*!
15156
    @brief returns an iterator to the reverse-beginning
15157
15158
    Returns an iterator to the reverse-beginning; that is, the last element.
15159
15160
    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
15161
15162
    @complexity Constant.
15163
15164
    @requirement This function helps `basic_json` satisfying the
15165
    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
15166
    requirements:
15167
    - The complexity is constant.
15168
    - Has the semantics of `reverse_iterator(end())`.
15169
15170
    @liveexample{The following code shows an example for `rbegin()`.,rbegin}
15171
15172
    @sa @ref crbegin() -- returns a const reverse iterator to the beginning
15173
    @sa @ref rend() -- returns a reverse iterator to the end
15174
    @sa @ref crend() -- returns a const reverse iterator to the end
15175
15176
    @since version 1.0.0
15177
    */
15178
    reverse_iterator rbegin() noexcept
15179
    {
15180
        return reverse_iterator(end());
15181
    }
15182
15183
    /*!
15184
    @copydoc basic_json::crbegin()
15185
    */
15186
    const_reverse_iterator rbegin() const noexcept
15187
    {
15188
        return crbegin();
15189
    }
15190
15191
    /*!
15192
    @brief returns an iterator to the reverse-end
15193
15194
    Returns an iterator to the reverse-end; that is, one before the first
15195
    element.
15196
15197
    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
15198
15199
    @complexity Constant.
15200
15201
    @requirement This function helps `basic_json` satisfying the
15202
    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
15203
    requirements:
15204
    - The complexity is constant.
15205
    - Has the semantics of `reverse_iterator(begin())`.
15206
15207
    @liveexample{The following code shows an example for `rend()`.,rend}
15208
15209
    @sa @ref crend() -- returns a const reverse iterator to the end
15210
    @sa @ref rbegin() -- returns a reverse iterator to the beginning
15211
    @sa @ref crbegin() -- returns a const reverse iterator to the beginning
15212
15213
    @since version 1.0.0
15214
    */
15215
    reverse_iterator rend() noexcept
15216
    {
15217
        return reverse_iterator(begin());
15218
    }
15219
15220
    /*!
15221
    @copydoc basic_json::crend()
15222
    */
15223
    const_reverse_iterator rend() const noexcept
15224
    {
15225
        return crend();
15226
    }
15227
15228
    /*!
15229
    @brief returns a const reverse iterator to the last element
15230
15231
    Returns a const iterator to the reverse-beginning; that is, the last
15232
    element.
15233
15234
    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
15235
15236
    @complexity Constant.
15237
15238
    @requirement This function helps `basic_json` satisfying the
15239
    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
15240
    requirements:
15241
    - The complexity is constant.
15242
    - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`.
15243
15244
    @liveexample{The following code shows an example for `crbegin()`.,crbegin}
15245
15246
    @sa @ref rbegin() -- returns a reverse iterator to the beginning
15247
    @sa @ref rend() -- returns a reverse iterator to the end
15248
    @sa @ref crend() -- returns a const reverse iterator to the end
15249
15250
    @since version 1.0.0
15251
    */
15252
    const_reverse_iterator crbegin() const noexcept
15253
    {
15254
        return const_reverse_iterator(cend());
15255
    }
15256
15257
    /*!
15258
    @brief returns a const reverse iterator to one before the first
15259
15260
    Returns a const reverse iterator to the reverse-end; that is, one before
15261
    the first element.
15262
15263
    @image html range-rbegin-rend.svg "Illustration from cppreference.com"
15264
15265
    @complexity Constant.
15266
15267
    @requirement This function helps `basic_json` satisfying the
15268
    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
15269
    requirements:
15270
    - The complexity is constant.
15271
    - Has the semantics of `const_cast<const basic_json&>(*this).rend()`.
15272
15273
    @liveexample{The following code shows an example for `crend()`.,crend}
15274
15275
    @sa @ref rend() -- returns a reverse iterator to the end
15276
    @sa @ref rbegin() -- returns a reverse iterator to the beginning
15277
    @sa @ref crbegin() -- returns a const reverse iterator to the beginning
15278
15279
    @since version 1.0.0
15280
    */
15281
    const_reverse_iterator crend() const noexcept
15282
    {
15283
        return const_reverse_iterator(cbegin());
15284
    }
15285
15286
  public:
15287
    /*!
15288
    @brief wrapper to access iterator member functions in range-based for
15289
15290
    This function allows to access @ref iterator::key() and @ref
15291
    iterator::value() during range-based for loops. In these loops, a
15292
    reference to the JSON values is returned, so there is no access to the
15293
    underlying iterator.
15294
15295
    For loop without iterator_wrapper:
15296
15297
    @code{cpp}
15298
    for (auto it = j_object.begin(); it != j_object.end(); ++it)
15299
    {
15300
        std::cout << "key: " << it.key() << ", value:" << it.value() << '\n';
15301
    }
15302
    @endcode
15303
15304
    Range-based for loop without iterator proxy:
15305
15306
    @code{cpp}
15307
    for (auto it : j_object)
15308
    {
15309
        // "it" is of type json::reference and has no key() member
15310
        std::cout << "value: " << it << '\n';
15311
    }
15312
    @endcode
15313
15314
    Range-based for loop with iterator proxy:
15315
15316
    @code{cpp}
15317
    for (auto it : json::iterator_wrapper(j_object))
15318
    {
15319
        std::cout << "key: " << it.key() << ", value:" << it.value() << '\n';
15320
    }
15321
    @endcode
15322
15323
    @note When iterating over an array, `key()` will return the index of the
15324
          element as string (see example).
15325
15326
    @param[in] ref  reference to a JSON value
15327
    @return iteration proxy object wrapping @a ref with an interface to use in
15328
            range-based for loops
15329
15330
    @liveexample{The following code shows how the wrapper is used,iterator_wrapper}
15331
15332
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
15333
    changes in the JSON value.
15334
15335
    @complexity Constant.
15336
15337
    @note The name of this function is not yet final and may change in the
15338
    future.
15339
15340
    @deprecated This stream operator is deprecated and will be removed in
15341
                future 4.0.0 of the library. Please use @ref items() instead;
15342
                that is, replace `json::iterator_wrapper(j)` with `j.items()`.
15343
    */
15344
    JSON_DEPRECATED
15345
    static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept
15346
    {
15347
        return ref.items();
15348
    }
15349
15350
    /*!
15351
    @copydoc iterator_wrapper(reference)
15352
    */
15353
    JSON_DEPRECATED
15354
    static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept
15355
    {
15356
        return ref.items();
15357
    }
15358
15359
    /*!
15360
    @brief helper to access iterator member functions in range-based for
15361
15362
    This function allows to access @ref iterator::key() and @ref
15363
    iterator::value() during range-based for loops. In these loops, a
15364
    reference to the JSON values is returned, so there is no access to the
15365
    underlying iterator.
15366
15367
    For loop without `items()` function:
15368
15369
    @code{cpp}
15370
    for (auto it = j_object.begin(); it != j_object.end(); ++it)
15371
    {
15372
        std::cout << "key: " << it.key() << ", value:" << it.value() << '\n';
15373
    }
15374
    @endcode
15375
15376
    Range-based for loop without `items()` function:
15377
15378
    @code{cpp}
15379
    for (auto it : j_object)
15380
    {
15381
        // "it" is of type json::reference and has no key() member
15382
        std::cout << "value: " << it << '\n';
15383
    }
15384
    @endcode
15385
15386
    Range-based for loop with `items()` function:
15387
15388
    @code{cpp}
15389
    for (auto it : j_object.items())
15390
    {
15391
        std::cout << "key: " << it.key() << ", value:" << it.value() << '\n';
15392
    }
15393
    @endcode
15394
15395
    @note When iterating over an array, `key()` will return the index of the
15396
          element as string (see example). For primitive types (e.g., numbers),
15397
          `key()` returns an empty string.
15398
15399
    @return iteration proxy object wrapping @a ref with an interface to use in
15400
            range-based for loops
15401
15402
    @liveexample{The following code shows how the function is used.,items}
15403
15404
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
15405
    changes in the JSON value.
15406
15407
    @complexity Constant.
15408
15409
    @since version 3.1.0.
15410
    */
15411
    iteration_proxy<iterator> items() noexcept
15412
    {
15413
        return iteration_proxy<iterator>(*this);
15414
    }
15415
15416
    /*!
15417
    @copydoc items()
15418
    */
15419
    iteration_proxy<const_iterator> items() const noexcept
15420
    {
15421
        return iteration_proxy<const_iterator>(*this);
15422
    }
15423
15424
    /// @}
15425
15426
15427
    //////////////
15428
    // capacity //
15429
    //////////////
15430
15431
    /// @name capacity
15432
    /// @{
15433
15434
    /*!
15435
    @brief checks whether the container is empty.
15436
15437
    Checks if a JSON value has no elements (i.e. whether its @ref size is `0`).
15438
15439
    @return The return value depends on the different types and is
15440
            defined as follows:
15441
            Value type  | return value
15442
            ----------- | -------------
15443
            null        | `true`
15444
            boolean     | `false`
15445
            string      | `false`
15446
            number      | `false`
15447
            object      | result of function `object_t::empty()`
15448
            array       | result of function `array_t::empty()`
15449
15450
    @liveexample{The following code uses `empty()` to check if a JSON
15451
    object contains any elements.,empty}
15452
15453
    @complexity Constant, as long as @ref array_t and @ref object_t satisfy
15454
    the Container concept; that is, their `empty()` functions have constant
15455
    complexity.
15456
15457
    @iterators No changes.
15458
15459
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
15460
15461
    @note This function does not return whether a string stored as JSON value
15462
    is empty - it returns whether the JSON container itself is empty which is
15463
    false in the case of a string.
15464
15465
    @requirement This function helps `basic_json` satisfying the
15466
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
15467
    requirements:
15468
    - The complexity is constant.
15469
    - Has the semantics of `begin() == end()`.
15470
15471
    @sa @ref size() -- returns the number of elements
15472
15473
    @since version 1.0.0
15474
    */
15475
    bool empty() const noexcept
15476
    {
15477
        switch (m_type)
15478
        {
15479
            case value_t::null:
15480
            {
15481
                // null values are empty
15482
                return true;
15483
            }
15484
15485
            case value_t::array:
15486
            {
15487
                // delegate call to array_t::empty()
15488
                return m_value.array->empty();
15489
            }
15490
15491
            case value_t::object:
15492
            {
15493
                // delegate call to object_t::empty()
15494
                return m_value.object->empty();
15495
            }
15496
15497
            default:
15498
            {
15499
                // all other types are nonempty
15500
                return false;
15501
            }
15502
        }
15503
    }
15504
15505
    /*!
15506
    @brief returns the number of elements
15507
15508
    Returns the number of elements in a JSON value.
15509
15510
    @return The return value depends on the different types and is
15511
            defined as follows:
15512
            Value type  | return value
15513
            ----------- | -------------
15514
            null        | `0`
15515
            boolean     | `1`
15516
            string      | `1`
15517
            number      | `1`
15518
            object      | result of function object_t::size()
15519
            array       | result of function array_t::size()
15520
15521
    @liveexample{The following code calls `size()` on the different value
15522
    types.,size}
15523
15524
    @complexity Constant, as long as @ref array_t and @ref object_t satisfy
15525
    the Container concept; that is, their size() functions have constant
15526
    complexity.
15527
15528
    @iterators No changes.
15529
15530
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
15531
15532
    @note This function does not return the length of a string stored as JSON
15533
    value - it returns the number of elements in the JSON value which is 1 in
15534
    the case of a string.
15535
15536
    @requirement This function helps `basic_json` satisfying the
15537
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
15538
    requirements:
15539
    - The complexity is constant.
15540
    - Has the semantics of `std::distance(begin(), end())`.
15541
15542
    @sa @ref empty() -- checks whether the container is empty
15543
    @sa @ref max_size() -- returns the maximal number of elements
15544
15545
    @since version 1.0.0
15546
    */
15547
    size_type size() const noexcept
15548
132
    {
15549
132
        switch (m_type)
15550
132
        {
15551
132
            case value_t::null:
15552
52
            {
15553
52
                // null values are empty
15554
52
                return 0;
15555
132
            }
15556
132
15557
132
            case value_t::array:
15558
80
            {
15559
80
                // delegate call to array_t::size()
15560
80
                return m_value.array->size();
15561
132
            }
15562
132
15563
132
            case value_t::object:
15564
0
            {
15565
0
                // delegate call to object_t::size()
15566
0
                return m_value.object->size();
15567
132
            }
15568
132
15569
132
            default:
15570
0
            {
15571
0
                // all other types have size 1
15572
0
                return 1;
15573
0
            }
15574
0
        }
15575
0
    }
15576
15577
    /*!
15578
    @brief returns the maximum possible number of elements
15579
15580
    Returns the maximum number of elements a JSON value is able to hold due to
15581
    system or library implementation limitations, i.e. `std::distance(begin(),
15582
    end())` for the JSON value.
15583
15584
    @return The return value depends on the different types and is
15585
            defined as follows:
15586
            Value type  | return value
15587
            ----------- | -------------
15588
            null        | `0` (same as `size()`)
15589
            boolean     | `1` (same as `size()`)
15590
            string      | `1` (same as `size()`)
15591
            number      | `1` (same as `size()`)
15592
            object      | result of function `object_t::max_size()`
15593
            array       | result of function `array_t::max_size()`
15594
15595
    @liveexample{The following code calls `max_size()` on the different value
15596
    types. Note the output is implementation specific.,max_size}
15597
15598
    @complexity Constant, as long as @ref array_t and @ref object_t satisfy
15599
    the Container concept; that is, their `max_size()` functions have constant
15600
    complexity.
15601
15602
    @iterators No changes.
15603
15604
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
15605
15606
    @requirement This function helps `basic_json` satisfying the
15607
    [Container](https://en.cppreference.com/w/cpp/named_req/Container)
15608
    requirements:
15609
    - The complexity is constant.
15610
    - Has the semantics of returning `b.size()` where `b` is the largest
15611
      possible JSON value.
15612
15613
    @sa @ref size() -- returns the number of elements
15614
15615
    @since version 1.0.0
15616
    */
15617
    size_type max_size() const noexcept
15618
0
    {
15619
0
        switch (m_type)
15620
0
        {
15621
0
            case value_t::array:
15622
0
            {
15623
0
                // delegate call to array_t::max_size()
15624
0
                return m_value.array->max_size();
15625
0
            }
15626
0
15627
0
            case value_t::object:
15628
0
            {
15629
0
                // delegate call to object_t::max_size()
15630
0
                return m_value.object->max_size();
15631
0
            }
15632
0
15633
0
            default:
15634
0
            {
15635
0
                // all other types have max_size() == size()
15636
0
                return size();
15637
0
            }
15638
0
        }
15639
0
    }
15640
15641
    /// @}
15642
15643
15644
    ///////////////
15645
    // modifiers //
15646
    ///////////////
15647
15648
    /// @name modifiers
15649
    /// @{
15650
15651
    /*!
15652
    @brief clears the contents
15653
15654
    Clears the content of a JSON value and resets it to the default value as
15655
    if @ref basic_json(value_t) would have been called with the current value
15656
    type from @ref type():
15657
15658
    Value type  | initial value
15659
    ----------- | -------------
15660
    null        | `null`
15661
    boolean     | `false`
15662
    string      | `""`
15663
    number      | `0`
15664
    object      | `{}`
15665
    array       | `[]`
15666
15667
    @post Has the same effect as calling
15668
    @code {.cpp}
15669
    *this = basic_json(type());
15670
    @endcode
15671
15672
    @liveexample{The example below shows the effect of `clear()` to different
15673
    JSON types.,clear}
15674
15675
    @complexity Linear in the size of the JSON value.
15676
15677
    @iterators All iterators, pointers and references related to this container
15678
               are invalidated.
15679
15680
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
15681
15682
    @sa @ref basic_json(value_t) -- constructor that creates an object with the
15683
        same value than calling `clear()`
15684
15685
    @since version 1.0.0
15686
    */
15687
    void clear() noexcept
15688
    {
15689
        switch (m_type)
15690
        {
15691
            case value_t::number_integer:
15692
            {
15693
                m_value.number_integer = 0;
15694
                break;
15695
            }
15696
15697
            case value_t::number_unsigned:
15698
            {
15699
                m_value.number_unsigned = 0;
15700
                break;
15701
            }
15702
15703
            case value_t::number_float:
15704
            {
15705
                m_value.number_float = 0.0;
15706
                break;
15707
            }
15708
15709
            case value_t::boolean:
15710
            {
15711
                m_value.boolean = false;
15712
                break;
15713
            }
15714
15715
            case value_t::string:
15716
            {
15717
                m_value.string->clear();
15718
                break;
15719
            }
15720
15721
            case value_t::array:
15722
            {
15723
                m_value.array->clear();
15724
                break;
15725
            }
15726
15727
            case value_t::object:
15728
            {
15729
                m_value.object->clear();
15730
                break;
15731
            }
15732
15733
            default:
15734
                break;
15735
        }
15736
    }
15737
15738
    /*!
15739
    @brief add an object to an array
15740
15741
    Appends the given element @a val to the end of the JSON value. If the
15742
    function is called on a JSON null value, an empty array is created before
15743
    appending @a val.
15744
15745
    @param[in] val the value to add to the JSON array
15746
15747
    @throw type_error.308 when called on a type other than JSON array or
15748
    null; example: `"cannot use push_back() with number"`
15749
15750
    @complexity Amortized constant.
15751
15752
    @liveexample{The example shows how `push_back()` and `+=` can be used to
15753
    add elements to a JSON array. Note how the `null` value was silently
15754
    converted to a JSON array.,push_back}
15755
15756
    @since version 1.0.0
15757
    */
15758
    void push_back(basic_json&& val)
15759
    {
15760
        // push_back only works for null objects or arrays
15761
        if (JSON_UNLIKELY(not(is_null() or is_array())))
15762
        {
15763
            JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name())));
15764
        }
15765
15766
        // transform null object into an array
15767
        if (is_null())
15768
        {
15769
            m_type = value_t::array;
15770
            m_value = value_t::array;
15771
            assert_invariant();
15772
        }
15773
15774
        // add element to array (move semantics)
15775
        m_value.array->push_back(std::move(val));
15776
        // invalidate object
15777
        val.m_type = value_t::null;
15778
    }
15779
15780
    /*!
15781
    @brief add an object to an array
15782
    @copydoc push_back(basic_json&&)
15783
    */
15784
    reference operator+=(basic_json&& val)
15785
    {
15786
        push_back(std::move(val));
15787
        return *this;
15788
    }
15789
15790
    /*!
15791
    @brief add an object to an array
15792
    @copydoc push_back(basic_json&&)
15793
    */
15794
    void push_back(const basic_json& val)
15795
    {
15796
        // push_back only works for null objects or arrays
15797
        if (JSON_UNLIKELY(not(is_null() or is_array())))
15798
        {
15799
            JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name())));
15800
        }
15801
15802
        // transform null object into an array
15803
        if (is_null())
15804
        {
15805
            m_type = value_t::array;
15806
            m_value = value_t::array;
15807
            assert_invariant();
15808
        }
15809
15810
        // add element to array
15811
        m_value.array->push_back(val);
15812
    }
15813
15814
    /*!
15815
    @brief add an object to an array
15816
    @copydoc push_back(basic_json&&)
15817
    */
15818
    reference operator+=(const basic_json& val)
15819
    {
15820
        push_back(val);
15821
        return *this;
15822
    }
15823
15824
    /*!
15825
    @brief add an object to an object
15826
15827
    Inserts the given element @a val to the JSON object. If the function is
15828
    called on a JSON null value, an empty object is created before inserting
15829
    @a val.
15830
15831
    @param[in] val the value to add to the JSON object
15832
15833
    @throw type_error.308 when called on a type other than JSON object or
15834
    null; example: `"cannot use push_back() with number"`
15835
15836
    @complexity Logarithmic in the size of the container, O(log(`size()`)).
15837
15838
    @liveexample{The example shows how `push_back()` and `+=` can be used to
15839
    add elements to a JSON object. Note how the `null` value was silently
15840
    converted to a JSON object.,push_back__object_t__value}
15841
15842
    @since version 1.0.0
15843
    */
15844
    void push_back(const typename object_t::value_type& val)
15845
    {
15846
        // push_back only works for null objects or objects
15847
        if (JSON_UNLIKELY(not(is_null() or is_object())))
15848
        {
15849
            JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name())));
15850
        }
15851
15852
        // transform null object into an object
15853
        if (is_null())
15854
        {
15855
            m_type = value_t::object;
15856
            m_value = value_t::object;
15857
            assert_invariant();
15858
        }
15859
15860
        // add element to array
15861
        m_value.object->insert(val);
15862
    }
15863
15864
    /*!
15865
    @brief add an object to an object
15866
    @copydoc push_back(const typename object_t::value_type&)
15867
    */
15868
    reference operator+=(const typename object_t::value_type& val)
15869
    {
15870
        push_back(val);
15871
        return *this;
15872
    }
15873
15874
    /*!
15875
    @brief add an object to an object
15876
15877
    This function allows to use `push_back` with an initializer list. In case
15878
15879
    1. the current value is an object,
15880
    2. the initializer list @a init contains only two elements, and
15881
    3. the first element of @a init is a string,
15882
15883
    @a init is converted into an object element and added using
15884
    @ref push_back(const typename object_t::value_type&). Otherwise, @a init
15885
    is converted to a JSON value and added using @ref push_back(basic_json&&).
15886
15887
    @param[in] init  an initializer list
15888
15889
    @complexity Linear in the size of the initializer list @a init.
15890
15891
    @note This function is required to resolve an ambiguous overload error,
15892
          because pairs like `{"key", "value"}` can be both interpreted as
15893
          `object_t::value_type` or `std::initializer_list<basic_json>`, see
15894
          https://github.com/nlohmann/json/issues/235 for more information.
15895
15896
    @liveexample{The example shows how initializer lists are treated as
15897
    objects when possible.,push_back__initializer_list}
15898
    */
15899
    void push_back(initializer_list_t init)
15900
    {
15901
        if (is_object() and init.size() == 2 and (*init.begin())->is_string())
15902
        {
15903
            basic_json&& key = init.begin()->moved_or_copied();
15904
            push_back(typename object_t::value_type(
15905
                          std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));
15906
        }
15907
        else
15908
        {
15909
            push_back(basic_json(init));
15910
        }
15911
    }
15912
15913
    /*!
15914
    @brief add an object to an object
15915
    @copydoc push_back(initializer_list_t)
15916
    */
15917
    reference operator+=(initializer_list_t init)
15918
    {
15919
        push_back(init);
15920
        return *this;
15921
    }
15922
15923
    /*!
15924
    @brief add an object to an array
15925
15926
    Creates a JSON value from the passed parameters @a args to the end of the
15927
    JSON value. If the function is called on a JSON null value, an empty array
15928
    is created before appending the value created from @a args.
15929
15930
    @param[in] args arguments to forward to a constructor of @ref basic_json
15931
    @tparam Args compatible types to create a @ref basic_json object
15932
15933
    @throw type_error.311 when called on a type other than JSON array or
15934
    null; example: `"cannot use emplace_back() with number"`
15935
15936
    @complexity Amortized constant.
15937
15938
    @liveexample{The example shows how `push_back()` can be used to add
15939
    elements to a JSON array. Note how the `null` value was silently converted
15940
    to a JSON array.,emplace_back}
15941
15942
    @since version 2.0.8
15943
    */
15944
    template<class... Args>
15945
    void emplace_back(Args&& ... args)
15946
    {
15947
        // emplace_back only works for null objects or arrays
15948
        if (JSON_UNLIKELY(not(is_null() or is_array())))
15949
        {
15950
            JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name())));
15951
        }
15952
15953
        // transform null object into an array
15954
        if (is_null())
15955
        {
15956
            m_type = value_t::array;
15957
            m_value = value_t::array;
15958
            assert_invariant();
15959
        }
15960
15961
        // add element to array (perfect forwarding)
15962
        m_value.array->emplace_back(std::forward<Args>(args)...);
15963
    }
15964
15965
    /*!
15966
    @brief add an object to an object if key does not exist
15967
15968
    Inserts a new element into a JSON object constructed in-place with the
15969
    given @a args if there is no element with the key in the container. If the
15970
    function is called on a JSON null value, an empty object is created before
15971
    appending the value created from @a args.
15972
15973
    @param[in] args arguments to forward to a constructor of @ref basic_json
15974
    @tparam Args compatible types to create a @ref basic_json object
15975
15976
    @return a pair consisting of an iterator to the inserted element, or the
15977
            already-existing element if no insertion happened, and a bool
15978
            denoting whether the insertion took place.
15979
15980
    @throw type_error.311 when called on a type other than JSON object or
15981
    null; example: `"cannot use emplace() with number"`
15982
15983
    @complexity Logarithmic in the size of the container, O(log(`size()`)).
15984
15985
    @liveexample{The example shows how `emplace()` can be used to add elements
15986
    to a JSON object. Note how the `null` value was silently converted to a
15987
    JSON object. Further note how no value is added if there was already one
15988
    value stored with the same key.,emplace}
15989
15990
    @since version 2.0.8
15991
    */
15992
    template<class... Args>
15993
    std::pair<iterator, bool> emplace(Args&& ... args)
15994
    {
15995
        // emplace only works for null objects or arrays
15996
        if (JSON_UNLIKELY(not(is_null() or is_object())))
15997
        {
15998
            JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name())));
15999
        }
16000
16001
        // transform null object into an object
16002
        if (is_null())
16003
        {
16004
            m_type = value_t::object;
16005
            m_value = value_t::object;
16006
            assert_invariant();
16007
        }
16008
16009
        // add element to array (perfect forwarding)
16010
        auto res = m_value.object->emplace(std::forward<Args>(args)...);
16011
        // create result iterator and set iterator to the result of emplace
16012
        auto it = begin();
16013
        it.m_it.object_iterator = res.first;
16014
16015
        // return pair of iterator and boolean
16016
        return {it, res.second};
16017
    }
16018
16019
    /*!
16020
    @brief inserts element
16021
16022
    Inserts element @a val before iterator @a pos.
16023
16024
    @param[in] pos iterator before which the content will be inserted; may be
16025
    the end() iterator
16026
    @param[in] val element to insert
16027
    @return iterator pointing to the inserted @a val.
16028
16029
    @throw type_error.309 if called on JSON values other than arrays;
16030
    example: `"cannot use insert() with string"`
16031
    @throw invalid_iterator.202 if @a pos is not an iterator of *this;
16032
    example: `"iterator does not fit current value"`
16033
16034
    @complexity Constant plus linear in the distance between @a pos and end of
16035
    the container.
16036
16037
    @liveexample{The example shows how `insert()` is used.,insert}
16038
16039
    @since version 1.0.0
16040
    */
16041
    iterator insert(const_iterator pos, const basic_json& val)
16042
    {
16043
        // insert only works for arrays
16044
        if (JSON_LIKELY(is_array()))
16045
        {
16046
            // check if iterator pos fits to this JSON value
16047
            if (JSON_UNLIKELY(pos.m_object != this))
16048
            {
16049
                JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
16050
            }
16051
16052
            // insert to array and return iterator
16053
            iterator result(this);
16054
            result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
16055
            return result;
16056
        }
16057
16058
        JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
16059
    }
16060
16061
    /*!
16062
    @brief inserts element
16063
    @copydoc insert(const_iterator, const basic_json&)
16064
    */
16065
    iterator insert(const_iterator pos, basic_json&& val)
16066
    {
16067
        return insert(pos, val);
16068
    }
16069
16070
    /*!
16071
    @brief inserts elements
16072
16073
    Inserts @a cnt copies of @a val before iterator @a pos.
16074
16075
    @param[in] pos iterator before which the content will be inserted; may be
16076
    the end() iterator
16077
    @param[in] cnt number of copies of @a val to insert
16078
    @param[in] val element to insert
16079
    @return iterator pointing to the first element inserted, or @a pos if
16080
    `cnt==0`
16081
16082
    @throw type_error.309 if called on JSON values other than arrays; example:
16083
    `"cannot use insert() with string"`
16084
    @throw invalid_iterator.202 if @a pos is not an iterator of *this;
16085
    example: `"iterator does not fit current value"`
16086
16087
    @complexity Linear in @a cnt plus linear in the distance between @a pos
16088
    and end of the container.
16089
16090
    @liveexample{The example shows how `insert()` is used.,insert__count}
16091
16092
    @since version 1.0.0
16093
    */
16094
    iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
16095
    {
16096
        // insert only works for arrays
16097
        if (JSON_LIKELY(is_array()))
16098
        {
16099
            // check if iterator pos fits to this JSON value
16100
            if (JSON_UNLIKELY(pos.m_object != this))
16101
            {
16102
                JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
16103
            }
16104
16105
            // insert to array and return iterator
16106
            iterator result(this);
16107
            result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
16108
            return result;
16109
        }
16110
16111
        JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
16112
    }
16113
16114
    /*!
16115
    @brief inserts elements
16116
16117
    Inserts elements from range `[first, last)` before iterator @a pos.
16118
16119
    @param[in] pos iterator before which the content will be inserted; may be
16120
    the end() iterator
16121
    @param[in] first begin of the range of elements to insert
16122
    @param[in] last end of the range of elements to insert
16123
16124
    @throw type_error.309 if called on JSON values other than arrays; example:
16125
    `"cannot use insert() with string"`
16126
    @throw invalid_iterator.202 if @a pos is not an iterator of *this;
16127
    example: `"iterator does not fit current value"`
16128
    @throw invalid_iterator.210 if @a first and @a last do not belong to the
16129
    same JSON value; example: `"iterators do not fit"`
16130
    @throw invalid_iterator.211 if @a first or @a last are iterators into
16131
    container for which insert is called; example: `"passed iterators may not
16132
    belong to container"`
16133
16134
    @return iterator pointing to the first element inserted, or @a pos if
16135
    `first==last`
16136
16137
    @complexity Linear in `std::distance(first, last)` plus linear in the
16138
    distance between @a pos and end of the container.
16139
16140
    @liveexample{The example shows how `insert()` is used.,insert__range}
16141
16142
    @since version 1.0.0
16143
    */
16144
    iterator insert(const_iterator pos, const_iterator first, const_iterator last)
16145
    {
16146
        // insert only works for arrays
16147
        if (JSON_UNLIKELY(not is_array()))
16148
        {
16149
            JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
16150
        }
16151
16152
        // check if iterator pos fits to this JSON value
16153
        if (JSON_UNLIKELY(pos.m_object != this))
16154
        {
16155
            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
16156
        }
16157
16158
        // check if range iterators belong to the same JSON object
16159
        if (JSON_UNLIKELY(first.m_object != last.m_object))
16160
        {
16161
            JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
16162
        }
16163
16164
        if (JSON_UNLIKELY(first.m_object == this))
16165
        {
16166
            JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container"));
16167
        }
16168
16169
        // insert to array and return iterator
16170
        iterator result(this);
16171
        result.m_it.array_iterator = m_value.array->insert(
16172
                                         pos.m_it.array_iterator,
16173
                                         first.m_it.array_iterator,
16174
                                         last.m_it.array_iterator);
16175
        return result;
16176
    }
16177
16178
    /*!
16179
    @brief inserts elements
16180
16181
    Inserts elements from initializer list @a ilist before iterator @a pos.
16182
16183
    @param[in] pos iterator before which the content will be inserted; may be
16184
    the end() iterator
16185
    @param[in] ilist initializer list to insert the values from
16186
16187
    @throw type_error.309 if called on JSON values other than arrays; example:
16188
    `"cannot use insert() with string"`
16189
    @throw invalid_iterator.202 if @a pos is not an iterator of *this;
16190
    example: `"iterator does not fit current value"`
16191
16192
    @return iterator pointing to the first element inserted, or @a pos if
16193
    `ilist` is empty
16194
16195
    @complexity Linear in `ilist.size()` plus linear in the distance between
16196
    @a pos and end of the container.
16197
16198
    @liveexample{The example shows how `insert()` is used.,insert__ilist}
16199
16200
    @since version 1.0.0
16201
    */
16202
    iterator insert(const_iterator pos, initializer_list_t ilist)
16203
    {
16204
        // insert only works for arrays
16205
        if (JSON_UNLIKELY(not is_array()))
16206
        {
16207
            JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
16208
        }
16209
16210
        // check if iterator pos fits to this JSON value
16211
        if (JSON_UNLIKELY(pos.m_object != this))
16212
        {
16213
            JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
16214
        }
16215
16216
        // insert to array and return iterator
16217
        iterator result(this);
16218
        result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end());
16219
        return result;
16220
    }
16221
16222
    /*!
16223
    @brief inserts elements
16224
16225
    Inserts elements from range `[first, last)`.
16226
16227
    @param[in] first begin of the range of elements to insert
16228
    @param[in] last end of the range of elements to insert
16229
16230
    @throw type_error.309 if called on JSON values other than objects; example:
16231
    `"cannot use insert() with string"`
16232
    @throw invalid_iterator.202 if iterator @a first or @a last does does not
16233
    point to an object; example: `"iterators first and last must point to
16234
    objects"`
16235
    @throw invalid_iterator.210 if @a first and @a last do not belong to the
16236
    same JSON value; example: `"iterators do not fit"`
16237
16238
    @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number
16239
    of elements to insert.
16240
16241
    @liveexample{The example shows how `insert()` is used.,insert__range_object}
16242
16243
    @since version 3.0.0
16244
    */
16245
    void insert(const_iterator first, const_iterator last)
16246
    {
16247
        // insert only works for objects
16248
        if (JSON_UNLIKELY(not is_object()))
16249
        {
16250
            JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
16251
        }
16252
16253
        // check if range iterators belong to the same JSON object
16254
        if (JSON_UNLIKELY(first.m_object != last.m_object))
16255
        {
16256
            JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
16257
        }
16258
16259
        // passed iterators must belong to objects
16260
        if (JSON_UNLIKELY(not first.m_object->is_object()))
16261
        {
16262
            JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
16263
        }
16264
16265
        m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
16266
    }
16267
16268
    /*!
16269
    @brief updates a JSON object from another object, overwriting existing keys
16270
16271
    Inserts all values from JSON object @a j and overwrites existing keys.
16272
16273
    @param[in] j  JSON object to read values from
16274
16275
    @throw type_error.312 if called on JSON values other than objects; example:
16276
    `"cannot use update() with string"`
16277
16278
    @complexity O(N*log(size() + N)), where N is the number of elements to
16279
                insert.
16280
16281
    @liveexample{The example shows how `update()` is used.,update}
16282
16283
    @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update
16284
16285
    @since version 3.0.0
16286
    */
16287
    void update(const_reference j)
16288
    {
16289
        // implicitly convert null value to an empty object
16290
        if (is_null())
16291
        {
16292
            m_type = value_t::object;
16293
            m_value.object = create<object_t>();
16294
            assert_invariant();
16295
        }
16296
16297
        if (JSON_UNLIKELY(not is_object()))
16298
        {
16299
            JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name())));
16300
        }
16301
        if (JSON_UNLIKELY(not j.is_object()))
16302
        {
16303
            JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name())));
16304
        }
16305
16306
        for (auto it = j.cbegin(); it != j.cend(); ++it)
16307
        {
16308
            m_value.object->operator[](it.key()) = it.value();
16309
        }
16310
    }
16311
16312
    /*!
16313
    @brief updates a JSON object from another object, overwriting existing keys
16314
16315
    Inserts all values from from range `[first, last)` and overwrites existing
16316
    keys.
16317
16318
    @param[in] first begin of the range of elements to insert
16319
    @param[in] last end of the range of elements to insert
16320
16321
    @throw type_error.312 if called on JSON values other than objects; example:
16322
    `"cannot use update() with string"`
16323
    @throw invalid_iterator.202 if iterator @a first or @a last does does not
16324
    point to an object; example: `"iterators first and last must point to
16325
    objects"`
16326
    @throw invalid_iterator.210 if @a first and @a last do not belong to the
16327
    same JSON value; example: `"iterators do not fit"`
16328
16329
    @complexity O(N*log(size() + N)), where N is the number of elements to
16330
                insert.
16331
16332
    @liveexample{The example shows how `update()` is used__range.,update}
16333
16334
    @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update
16335
16336
    @since version 3.0.0
16337
    */
16338
    void update(const_iterator first, const_iterator last)
16339
    {
16340
        // implicitly convert null value to an empty object
16341
        if (is_null())
16342
        {
16343
            m_type = value_t::object;
16344
            m_value.object = create<object_t>();
16345
            assert_invariant();
16346
        }
16347
16348
        if (JSON_UNLIKELY(not is_object()))
16349
        {
16350
            JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name())));
16351
        }
16352
16353
        // check if range iterators belong to the same JSON object
16354
        if (JSON_UNLIKELY(first.m_object != last.m_object))
16355
        {
16356
            JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
16357
        }
16358
16359
        // passed iterators must belong to objects
16360
        if (JSON_UNLIKELY(not first.m_object->is_object()
16361
                          or not last.m_object->is_object()))
16362
        {
16363
            JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
16364
        }
16365
16366
        for (auto it = first; it != last; ++it)
16367
        {
16368
            m_value.object->operator[](it.key()) = it.value();
16369
        }
16370
    }
16371
16372
    /*!
16373
    @brief exchanges the values
16374
16375
    Exchanges the contents of the JSON value with those of @a other. Does not
16376
    invoke any move, copy, or swap operations on individual elements. All
16377
    iterators and references remain valid. The past-the-end iterator is
16378
    invalidated.
16379
16380
    @param[in,out] other JSON value to exchange the contents with
16381
16382
    @complexity Constant.
16383
16384
    @liveexample{The example below shows how JSON values can be swapped with
16385
    `swap()`.,swap__reference}
16386
16387
    @since version 1.0.0
16388
    */
16389
    void swap(reference other) noexcept (
16390
        std::is_nothrow_move_constructible<value_t>::value and
16391
        std::is_nothrow_move_assignable<value_t>::value and
16392
        std::is_nothrow_move_constructible<json_value>::value and
16393
        std::is_nothrow_move_assignable<json_value>::value
16394
    )
16395
0
    {
16396
0
        std::swap(m_type, other.m_type);
16397
0
        std::swap(m_value, other.m_value);
16398
0
        assert_invariant();
16399
0
    }
16400
16401
    /*!
16402
    @brief exchanges the values
16403
16404
    Exchanges the contents of a JSON array with those of @a other. Does not
16405
    invoke any move, copy, or swap operations on individual elements. All
16406
    iterators and references remain valid. The past-the-end iterator is
16407
    invalidated.
16408
16409
    @param[in,out] other array to exchange the contents with
16410
16411
    @throw type_error.310 when JSON value is not an array; example: `"cannot
16412
    use swap() with string"`
16413
16414
    @complexity Constant.
16415
16416
    @liveexample{The example below shows how arrays can be swapped with
16417
    `swap()`.,swap__array_t}
16418
16419
    @since version 1.0.0
16420
    */
16421
    void swap(array_t& other)
16422
    {
16423
        // swap only works for arrays
16424
        if (JSON_LIKELY(is_array()))
16425
        {
16426
            std::swap(*(m_value.array), other);
16427
        }
16428
        else
16429
        {
16430
            JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name())));
16431
        }
16432
    }
16433
16434
    /*!
16435
    @brief exchanges the values
16436
16437
    Exchanges the contents of a JSON object with those of @a other. Does not
16438
    invoke any move, copy, or swap operations on individual elements. All
16439
    iterators and references remain valid. The past-the-end iterator is
16440
    invalidated.
16441
16442
    @param[in,out] other object to exchange the contents with
16443
16444
    @throw type_error.310 when JSON value is not an object; example:
16445
    `"cannot use swap() with string"`
16446
16447
    @complexity Constant.
16448
16449
    @liveexample{The example below shows how objects can be swapped with
16450
    `swap()`.,swap__object_t}
16451
16452
    @since version 1.0.0
16453
    */
16454
    void swap(object_t& other)
16455
    {
16456
        // swap only works for objects
16457
        if (JSON_LIKELY(is_object()))
16458
        {
16459
            std::swap(*(m_value.object), other);
16460
        }
16461
        else
16462
        {
16463
            JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name())));
16464
        }
16465
    }
16466
16467
    /*!
16468
    @brief exchanges the values
16469
16470
    Exchanges the contents of a JSON string with those of @a other. Does not
16471
    invoke any move, copy, or swap operations on individual elements. All
16472
    iterators and references remain valid. The past-the-end iterator is
16473
    invalidated.
16474
16475
    @param[in,out] other string to exchange the contents with
16476
16477
    @throw type_error.310 when JSON value is not a string; example: `"cannot
16478
    use swap() with boolean"`
16479
16480
    @complexity Constant.
16481
16482
    @liveexample{The example below shows how strings can be swapped with
16483
    `swap()`.,swap__string_t}
16484
16485
    @since version 1.0.0
16486
    */
16487
    void swap(string_t& other)
16488
    {
16489
        // swap only works for strings
16490
        if (JSON_LIKELY(is_string()))
16491
        {
16492
            std::swap(*(m_value.string), other);
16493
        }
16494
        else
16495
        {
16496
            JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name())));
16497
        }
16498
    }
16499
16500
    /// @}
16501
16502
  public:
16503
    //////////////////////////////////////////
16504
    // lexicographical comparison operators //
16505
    //////////////////////////////////////////
16506
16507
    /// @name lexicographical comparison operators
16508
    /// @{
16509
16510
    /*!
16511
    @brief comparison: equal
16512
16513
    Compares two JSON values for equality according to the following rules:
16514
    - Two JSON values are equal if (1) they are from the same type and (2)
16515
      their stored values are the same according to their respective
16516
      `operator==`.
16517
    - Integer and floating-point numbers are automatically converted before
16518
      comparison. Note than two NaN values are always treated as unequal.
16519
    - Two JSON null values are equal.
16520
16521
    @note Floating-point inside JSON values numbers are compared with
16522
    `json::number_float_t::operator==` which is `double::operator==` by
16523
    default. To compare floating-point while respecting an epsilon, an alternative
16524
    [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39)
16525
    could be used, for instance
16526
    @code {.cpp}
16527
    template<typename T, typename = typename std::enable_if<std::is_floating_point<T>::value, T>::type>
16528
    inline bool is_same(T a, T b, T epsilon = std::numeric_limits<T>::epsilon()) noexcept
16529
    {
16530
        return std::abs(a - b) <= epsilon;
16531
    }
16532
    @endcode
16533
16534
    @note NaN values never compare equal to themselves or to other NaN values.
16535
16536
    @param[in] lhs  first JSON value to consider
16537
    @param[in] rhs  second JSON value to consider
16538
    @return whether the values @a lhs and @a rhs are equal
16539
16540
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
16541
16542
    @complexity Linear.
16543
16544
    @liveexample{The example demonstrates comparing several JSON
16545
    types.,operator__equal}
16546
16547
    @since version 1.0.0
16548
    */
16549
    friend bool operator==(const_reference lhs, const_reference rhs) noexcept
16550
40
    {
16551
40
        const auto lhs_type = lhs.type();
16552
40
        const auto rhs_type = rhs.type();
16553
40
16554
40
        if (lhs_type == rhs_type)
16555
40
        {
16556
40
            switch (lhs_type)
16557
40
            {
16558
40
                case value_t::array:
16559
0
                    return (*lhs.m_value.array == *rhs.m_value.array);
16560
40
16561
40
                case value_t::object:
16562
0
                    return (*lhs.m_value.object == *rhs.m_value.object);
16563
40
16564
40
                case value_t::null:
16565
0
                    return true;
16566
40
16567
40
                case value_t::string:
16568
40
                    return (*lhs.m_value.string == *rhs.m_value.string);
16569
40
16570
40
                case value_t::boolean:
16571
0
                    return (lhs.m_value.boolean == rhs.m_value.boolean);
16572
40
16573
40
                case value_t::number_integer:
16574
0
                    return (lhs.m_value.number_integer == rhs.m_value.number_integer);
16575
40
16576
40
                case value_t::number_unsigned:
16577
0
                    return (lhs.m_value.number_unsigned == rhs.m_value.number_unsigned);
16578
40
16579
40
                case value_t::number_float:
16580
0
                    return (lhs.m_value.number_float == rhs.m_value.number_float);
16581
40
16582
40
                default:
16583
0
                    return false;
16584
0
            }
16585
0
        }
16586
0
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
16587
0
        {
16588
0
            return (static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float);
16589
0
        }
16590
0
        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
16591
0
        {
16592
0
            return (lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer));
16593
0
        }
16594
0
        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
16595
0
        {
16596
0
            return (static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float);
16597
0
        }
16598
0
        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
16599
0
        {
16600
0
            return (lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned));
16601
0
        }
16602
0
        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
16603
0
        {
16604
0
            return (static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer);
16605
0
        }
16606
0
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
16607
0
        {
16608
0
            return (lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned));
16609
0
        }
16610
0
16611
0
        return false;
16612
0
    }
16613
16614
    /*!
16615
    @brief comparison: equal
16616
    @copydoc operator==(const_reference, const_reference)
16617
    */
16618
    template<typename ScalarType, typename std::enable_if<
16619
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16620
    friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept
16621
40
    {
16622
40
        return (lhs == basic_json(rhs));
16623
40
    }
16624
16625
    /*!
16626
    @brief comparison: equal
16627
    @copydoc operator==(const_reference, const_reference)
16628
    */
16629
    template<typename ScalarType, typename std::enable_if<
16630
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16631
    friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept
16632
    {
16633
        return (basic_json(lhs) == rhs);
16634
    }
16635
16636
    /*!
16637
    @brief comparison: not equal
16638
16639
    Compares two JSON values for inequality by calculating `not (lhs == rhs)`.
16640
16641
    @param[in] lhs  first JSON value to consider
16642
    @param[in] rhs  second JSON value to consider
16643
    @return whether the values @a lhs and @a rhs are not equal
16644
16645
    @complexity Linear.
16646
16647
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
16648
16649
    @liveexample{The example demonstrates comparing several JSON
16650
    types.,operator__notequal}
16651
16652
    @since version 1.0.0
16653
    */
16654
    friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
16655
    {
16656
        return not (lhs == rhs);
16657
    }
16658
16659
    /*!
16660
    @brief comparison: not equal
16661
    @copydoc operator!=(const_reference, const_reference)
16662
    */
16663
    template<typename ScalarType, typename std::enable_if<
16664
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16665
    friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept
16666
    {
16667
        return (lhs != basic_json(rhs));
16668
    }
16669
16670
    /*!
16671
    @brief comparison: not equal
16672
    @copydoc operator!=(const_reference, const_reference)
16673
    */
16674
    template<typename ScalarType, typename std::enable_if<
16675
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16676
    friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept
16677
    {
16678
        return (basic_json(lhs) != rhs);
16679
    }
16680
16681
    /*!
16682
    @brief comparison: less than
16683
16684
    Compares whether one JSON value @a lhs is less than another JSON value @a
16685
    rhs according to the following rules:
16686
    - If @a lhs and @a rhs have the same type, the values are compared using
16687
      the default `<` operator.
16688
    - Integer and floating-point numbers are automatically converted before
16689
      comparison
16690
    - In case @a lhs and @a rhs have different types, the values are ignored
16691
      and the order of the types is considered, see
16692
      @ref operator<(const value_t, const value_t).
16693
16694
    @param[in] lhs  first JSON value to consider
16695
    @param[in] rhs  second JSON value to consider
16696
    @return whether @a lhs is less than @a rhs
16697
16698
    @complexity Linear.
16699
16700
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
16701
16702
    @liveexample{The example demonstrates comparing several JSON
16703
    types.,operator__less}
16704
16705
    @since version 1.0.0
16706
    */
16707
    friend bool operator<(const_reference lhs, const_reference rhs) noexcept
16708
    {
16709
        const auto lhs_type = lhs.type();
16710
        const auto rhs_type = rhs.type();
16711
16712
        if (lhs_type == rhs_type)
16713
        {
16714
            switch (lhs_type)
16715
            {
16716
                case value_t::array:
16717
                    return (*lhs.m_value.array) < (*rhs.m_value.array);
16718
16719
                case value_t::object:
16720
                    return *lhs.m_value.object < *rhs.m_value.object;
16721
16722
                case value_t::null:
16723
                    return false;
16724
16725
                case value_t::string:
16726
                    return *lhs.m_value.string < *rhs.m_value.string;
16727
16728
                case value_t::boolean:
16729
                    return lhs.m_value.boolean < rhs.m_value.boolean;
16730
16731
                case value_t::number_integer:
16732
                    return lhs.m_value.number_integer < rhs.m_value.number_integer;
16733
16734
                case value_t::number_unsigned:
16735
                    return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned;
16736
16737
                case value_t::number_float:
16738
                    return lhs.m_value.number_float < rhs.m_value.number_float;
16739
16740
                default:
16741
                    return false;
16742
            }
16743
        }
16744
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
16745
        {
16746
            return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;
16747
        }
16748
        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
16749
        {
16750
            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);
16751
        }
16752
        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
16753
        {
16754
            return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;
16755
        }
16756
        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
16757
        {
16758
            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);
16759
        }
16760
        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
16761
        {
16762
            return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);
16763
        }
16764
        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
16765
        {
16766
            return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;
16767
        }
16768
16769
        // We only reach this line if we cannot compare values. In that case,
16770
        // we compare types. Note we have to call the operator explicitly,
16771
        // because MSVC has problems otherwise.
16772
        return operator<(lhs_type, rhs_type);
16773
    }
16774
16775
    /*!
16776
    @brief comparison: less than
16777
    @copydoc operator<(const_reference, const_reference)
16778
    */
16779
    template<typename ScalarType, typename std::enable_if<
16780
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16781
    friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept
16782
    {
16783
        return (lhs < basic_json(rhs));
16784
    }
16785
16786
    /*!
16787
    @brief comparison: less than
16788
    @copydoc operator<(const_reference, const_reference)
16789
    */
16790
    template<typename ScalarType, typename std::enable_if<
16791
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16792
    friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept
16793
    {
16794
        return (basic_json(lhs) < rhs);
16795
    }
16796
16797
    /*!
16798
    @brief comparison: less than or equal
16799
16800
    Compares whether one JSON value @a lhs is less than or equal to another
16801
    JSON value by calculating `not (rhs < lhs)`.
16802
16803
    @param[in] lhs  first JSON value to consider
16804
    @param[in] rhs  second JSON value to consider
16805
    @return whether @a lhs is less than or equal to @a rhs
16806
16807
    @complexity Linear.
16808
16809
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
16810
16811
    @liveexample{The example demonstrates comparing several JSON
16812
    types.,operator__greater}
16813
16814
    @since version 1.0.0
16815
    */
16816
    friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
16817
    {
16818
        return not (rhs < lhs);
16819
    }
16820
16821
    /*!
16822
    @brief comparison: less than or equal
16823
    @copydoc operator<=(const_reference, const_reference)
16824
    */
16825
    template<typename ScalarType, typename std::enable_if<
16826
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16827
    friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept
16828
    {
16829
        return (lhs <= basic_json(rhs));
16830
    }
16831
16832
    /*!
16833
    @brief comparison: less than or equal
16834
    @copydoc operator<=(const_reference, const_reference)
16835
    */
16836
    template<typename ScalarType, typename std::enable_if<
16837
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16838
    friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept
16839
    {
16840
        return (basic_json(lhs) <= rhs);
16841
    }
16842
16843
    /*!
16844
    @brief comparison: greater than
16845
16846
    Compares whether one JSON value @a lhs is greater than another
16847
    JSON value by calculating `not (lhs <= rhs)`.
16848
16849
    @param[in] lhs  first JSON value to consider
16850
    @param[in] rhs  second JSON value to consider
16851
    @return whether @a lhs is greater than to @a rhs
16852
16853
    @complexity Linear.
16854
16855
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
16856
16857
    @liveexample{The example demonstrates comparing several JSON
16858
    types.,operator__lessequal}
16859
16860
    @since version 1.0.0
16861
    */
16862
    friend bool operator>(const_reference lhs, const_reference rhs) noexcept
16863
    {
16864
        return not (lhs <= rhs);
16865
    }
16866
16867
    /*!
16868
    @brief comparison: greater than
16869
    @copydoc operator>(const_reference, const_reference)
16870
    */
16871
    template<typename ScalarType, typename std::enable_if<
16872
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16873
    friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept
16874
    {
16875
        return (lhs > basic_json(rhs));
16876
    }
16877
16878
    /*!
16879
    @brief comparison: greater than
16880
    @copydoc operator>(const_reference, const_reference)
16881
    */
16882
    template<typename ScalarType, typename std::enable_if<
16883
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16884
    friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept
16885
    {
16886
        return (basic_json(lhs) > rhs);
16887
    }
16888
16889
    /*!
16890
    @brief comparison: greater than or equal
16891
16892
    Compares whether one JSON value @a lhs is greater than or equal to another
16893
    JSON value by calculating `not (lhs < rhs)`.
16894
16895
    @param[in] lhs  first JSON value to consider
16896
    @param[in] rhs  second JSON value to consider
16897
    @return whether @a lhs is greater than or equal to @a rhs
16898
16899
    @complexity Linear.
16900
16901
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
16902
16903
    @liveexample{The example demonstrates comparing several JSON
16904
    types.,operator__greaterequal}
16905
16906
    @since version 1.0.0
16907
    */
16908
    friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
16909
    {
16910
        return not (lhs < rhs);
16911
    }
16912
16913
    /*!
16914
    @brief comparison: greater than or equal
16915
    @copydoc operator>=(const_reference, const_reference)
16916
    */
16917
    template<typename ScalarType, typename std::enable_if<
16918
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16919
    friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept
16920
    {
16921
        return (lhs >= basic_json(rhs));
16922
    }
16923
16924
    /*!
16925
    @brief comparison: greater than or equal
16926
    @copydoc operator>=(const_reference, const_reference)
16927
    */
16928
    template<typename ScalarType, typename std::enable_if<
16929
                 std::is_scalar<ScalarType>::value, int>::type = 0>
16930
    friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept
16931
    {
16932
        return (basic_json(lhs) >= rhs);
16933
    }
16934
16935
    /// @}
16936
16937
    ///////////////////
16938
    // serialization //
16939
    ///////////////////
16940
16941
    /// @name serialization
16942
    /// @{
16943
16944
    /*!
16945
    @brief serialize to stream
16946
16947
    Serialize the given JSON value @a j to the output stream @a o. The JSON
16948
    value will be serialized using the @ref dump member function.
16949
16950
    - The indentation of the output can be controlled with the member variable
16951
      `width` of the output stream @a o. For instance, using the manipulator
16952
      `std::setw(4)` on @a o sets the indentation level to `4` and the
16953
      serialization result is the same as calling `dump(4)`.
16954
16955
    - The indentation character can be controlled with the member variable
16956
      `fill` of the output stream @a o. For instance, the manipulator
16957
      `std::setfill('\\t')` sets indentation to use a tab character rather than
16958
      the default space character.
16959
16960
    @param[in,out] o  stream to serialize to
16961
    @param[in] j  JSON value to serialize
16962
16963
    @return the stream @a o
16964
16965
    @throw type_error.316 if a string stored inside the JSON value is not
16966
                          UTF-8 encoded
16967
16968
    @complexity Linear.
16969
16970
    @liveexample{The example below shows the serialization with different
16971
    parameters to `width` to adjust the indentation level.,operator_serialize}
16972
16973
    @since version 1.0.0; indentation character added in version 3.0.0
16974
    */
16975
    friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
16976
436
    {
16977
436
        // read width member and use it as indentation parameter if nonzero
16978
436
        const bool pretty_print = (o.width() > 0);
16979
436
        const auto indentation = (pretty_print ? o.width() : 0);
16980
436
16981
436
        // reset width to 0 for subsequent calls to this stream
16982
436
        o.width(0);
16983
436
16984
436
        // do the actual serialization
16985
436
        serializer s(detail::output_adapter<char>(o), o.fill());
16986
436
        s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));
16987
436
        return o;
16988
436
    }
16989
16990
    /*!
16991
    @brief serialize to stream
16992
    @deprecated This stream operator is deprecated and will be removed in
16993
                future 4.0.0 of the library. Please use
16994
                @ref operator<<(std::ostream&, const basic_json&)
16995
                instead; that is, replace calls like `j >> o;` with `o << j;`.
16996
    @since version 1.0.0; deprecated since version 3.0.0
16997
    */
16998
    JSON_DEPRECATED
16999
    friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
17000
    {
17001
        return o << j;
17002
    }
17003
17004
    /// @}
17005
17006
17007
    /////////////////////
17008
    // deserialization //
17009
    /////////////////////
17010
17011
    /// @name deserialization
17012
    /// @{
17013
17014
    /*!
17015
    @brief deserialize from a compatible input
17016
17017
    This function reads from a compatible input. Examples are:
17018
    - an array of 1-byte values
17019
    - strings with character/literal type with size of 1 byte
17020
    - input streams
17021
    - container with contiguous storage of 1-byte values. Compatible container
17022
      types include `std::vector`, `std::string`, `std::array`,
17023
      `std::valarray`, and `std::initializer_list`. Furthermore, C-style
17024
      arrays can be used with `std::begin()`/`std::end()`. User-defined
17025
      containers can be used as long as they implement random-access iterators
17026
      and a contiguous storage.
17027
17028
    @pre Each element of the container has a size of 1 byte. Violating this
17029
    precondition yields undefined behavior. **This precondition is enforced
17030
    with a static assertion.**
17031
17032
    @pre The container storage is contiguous. Violating this precondition
17033
    yields undefined behavior. **This precondition is enforced with an
17034
    assertion.**
17035
    @pre Each element of the container has a size of 1 byte. Violating this
17036
    precondition yields undefined behavior. **This precondition is enforced
17037
    with a static assertion.**
17038
17039
    @warning There is no way to enforce all preconditions at compile-time. If
17040
             the function is called with a noncompliant container and with
17041
             assertions switched off, the behavior is undefined and will most
17042
             likely yield segmentation violation.
17043
17044
    @param[in] i  input to read from
17045
    @param[in] cb  a parser callback function of type @ref parser_callback_t
17046
    which is used to control the deserialization by filtering unwanted values
17047
    (optional)
17048
17049
    @return result of the deserialization
17050
17051
    @throw parse_error.101 if a parse error occurs; example: `""unexpected end
17052
    of input; expected string literal""`
17053
    @throw parse_error.102 if to_unicode fails or surrogate error
17054
    @throw parse_error.103 if to_unicode fails
17055
17056
    @complexity Linear in the length of the input. The parser is a predictive
17057
    LL(1) parser. The complexity can be higher if the parser callback function
17058
    @a cb has a super-linear complexity.
17059
17060
    @note A UTF-8 byte order mark is silently ignored.
17061
17062
    @liveexample{The example below demonstrates the `parse()` function reading
17063
    from an array.,parse__array__parser_callback_t}
17064
17065
    @liveexample{The example below demonstrates the `parse()` function with
17066
    and without callback function.,parse__string__parser_callback_t}
17067
17068
    @liveexample{The example below demonstrates the `parse()` function with
17069
    and without callback function.,parse__istream__parser_callback_t}
17070
17071
    @liveexample{The example below demonstrates the `parse()` function reading
17072
    from a contiguous container.,parse__contiguouscontainer__parser_callback_t}
17073
17074
    @since version 2.0.3 (contiguous containers)
17075
    */
17076
    static basic_json parse(detail::input_adapter&& i,
17077
                            const parser_callback_t cb = nullptr,
17078
                            const bool allow_exceptions = true)
17079
2.59k
    {
17080
2.59k
        basic_json result;
17081
2.59k
        parser(i, cb, allow_exceptions).parse(true, result);
17082
2.59k
        return result;
17083
2.59k
    }
17084
17085
    static bool accept(detail::input_adapter&& i)
17086
    {
17087
        return parser(i).accept(true);
17088
    }
17089
17090
    /*!
17091
    @brief generate SAX events
17092
17093
    The SAX event lister must follow the interface of @ref json_sax.
17094
17095
    This function reads from a compatible input. Examples are:
17096
    - an array of 1-byte values
17097
    - strings with character/literal type with size of 1 byte
17098
    - input streams
17099
    - container with contiguous storage of 1-byte values. Compatible container
17100
      types include `std::vector`, `std::string`, `std::array`,
17101
      `std::valarray`, and `std::initializer_list`. Furthermore, C-style
17102
      arrays can be used with `std::begin()`/`std::end()`. User-defined
17103
      containers can be used as long as they implement random-access iterators
17104
      and a contiguous storage.
17105
17106
    @pre Each element of the container has a size of 1 byte. Violating this
17107
    precondition yields undefined behavior. **This precondition is enforced
17108
    with a static assertion.**
17109
17110
    @pre The container storage is contiguous. Violating this precondition
17111
    yields undefined behavior. **This precondition is enforced with an
17112
    assertion.**
17113
    @pre Each element of the container has a size of 1 byte. Violating this
17114
    precondition yields undefined behavior. **This precondition is enforced
17115
    with a static assertion.**
17116
17117
    @warning There is no way to enforce all preconditions at compile-time. If
17118
             the function is called with a noncompliant container and with
17119
             assertions switched off, the behavior is undefined and will most
17120
             likely yield segmentation violation.
17121
17122
    @param[in] i  input to read from
17123
    @param[in,out] sax  SAX event listener
17124
    @param[in] format  the format to parse (JSON, CBOR, MessagePack, or UBJSON)
17125
    @param[in] strict  whether the input has to be consumed completely
17126
17127
    @return return value of the last processed SAX event
17128
17129
    @throw parse_error.101 if a parse error occurs; example: `""unexpected end
17130
    of input; expected string literal""`
17131
    @throw parse_error.102 if to_unicode fails or surrogate error
17132
    @throw parse_error.103 if to_unicode fails
17133
17134
    @complexity Linear in the length of the input. The parser is a predictive
17135
    LL(1) parser. The complexity can be higher if the SAX consumer @a sax has
17136
    a super-linear complexity.
17137
17138
    @note A UTF-8 byte order mark is silently ignored.
17139
17140
    @liveexample{The example below demonstrates the `sax_parse()` function
17141
    reading from string and processing the events with a user-defined SAX
17142
    event consumer.,sax_parse}
17143
17144
    @since version 3.2.0
17145
    */
17146
    template <typename SAX>
17147
    static bool sax_parse(detail::input_adapter&& i, SAX* sax,
17148
                          input_format_t format = input_format_t::json,
17149
                          const bool strict = true)
17150
    {
17151
        assert(sax);
17152
        switch (format)
17153
        {
17154
            case input_format_t::json:
17155
                return parser(std::move(i)).sax_parse(sax, strict);
17156
            default:
17157
                return detail::binary_reader<basic_json, SAX>(std::move(i)).sax_parse(format, sax, strict);
17158
        }
17159
    }
17160
17161
    /*!
17162
    @brief deserialize from an iterator range with contiguous storage
17163
17164
    This function reads from an iterator range of a container with contiguous
17165
    storage of 1-byte values. Compatible container types include
17166
    `std::vector`, `std::string`, `std::array`, `std::valarray`, and
17167
    `std::initializer_list`. Furthermore, C-style arrays can be used with
17168
    `std::begin()`/`std::end()`. User-defined containers can be used as long
17169
    as they implement random-access iterators and a contiguous storage.
17170
17171
    @pre The iterator range is contiguous. Violating this precondition yields
17172
    undefined behavior. **This precondition is enforced with an assertion.**
17173
    @pre Each element in the range has a size of 1 byte. Violating this
17174
    precondition yields undefined behavior. **This precondition is enforced
17175
    with a static assertion.**
17176
17177
    @warning There is no way to enforce all preconditions at compile-time. If
17178
             the function is called with noncompliant iterators and with
17179
             assertions switched off, the behavior is undefined and will most
17180
             likely yield segmentation violation.
17181
17182
    @tparam IteratorType iterator of container with contiguous storage
17183
    @param[in] first  begin of the range to parse (included)
17184
    @param[in] last  end of the range to parse (excluded)
17185
    @param[in] cb  a parser callback function of type @ref parser_callback_t
17186
    which is used to control the deserialization by filtering unwanted values
17187
    (optional)
17188
    @param[in] allow_exceptions  whether to throw exceptions in case of a
17189
    parse error (optional, true by default)
17190
17191
    @return result of the deserialization
17192
17193
    @throw parse_error.101 in case of an unexpected token
17194
    @throw parse_error.102 if to_unicode fails or surrogate error
17195
    @throw parse_error.103 if to_unicode fails
17196
17197
    @complexity Linear in the length of the input. The parser is a predictive
17198
    LL(1) parser. The complexity can be higher if the parser callback function
17199
    @a cb has a super-linear complexity.
17200
17201
    @note A UTF-8 byte order mark is silently ignored.
17202
17203
    @liveexample{The example below demonstrates the `parse()` function reading
17204
    from an iterator range.,parse__iteratortype__parser_callback_t}
17205
17206
    @since version 2.0.3
17207
    */
17208
    template<class IteratorType, typename std::enable_if<
17209
                 std::is_base_of<
17210
                     std::random_access_iterator_tag,
17211
                     typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
17212
    static basic_json parse(IteratorType first, IteratorType last,
17213
                            const parser_callback_t cb = nullptr,
17214
                            const bool allow_exceptions = true)
17215
0
    {
17216
0
        basic_json result;
17217
0
        parser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result);
17218
0
        return result;
17219
0
    }
17220
17221
    template<class IteratorType, typename std::enable_if<
17222
                 std::is_base_of<
17223
                     std::random_access_iterator_tag,
17224
                     typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
17225
    static bool accept(IteratorType first, IteratorType last)
17226
    {
17227
        return parser(detail::input_adapter(first, last)).accept(true);
17228
    }
17229
17230
    template<class IteratorType, class SAX, typename std::enable_if<
17231
                 std::is_base_of<
17232
                     std::random_access_iterator_tag,
17233
                     typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
17234
    static bool sax_parse(IteratorType first, IteratorType last, SAX* sax)
17235
    {
17236
        return parser(detail::input_adapter(first, last)).sax_parse(sax);
17237
    }
17238
17239
    /*!
17240
    @brief deserialize from stream
17241
    @deprecated This stream operator is deprecated and will be removed in
17242
                version 4.0.0 of the library. Please use
17243
                @ref operator>>(std::istream&, basic_json&)
17244
                instead; that is, replace calls like `j << i;` with `i >> j;`.
17245
    @since version 1.0.0; deprecated since version 3.0.0
17246
    */
17247
    JSON_DEPRECATED
17248
    friend std::istream& operator<<(basic_json& j, std::istream& i)
17249
    {
17250
        return operator>>(i, j);
17251
    }
17252
17253
    /*!
17254
    @brief deserialize from stream
17255
17256
    Deserializes an input stream to a JSON value.
17257
17258
    @param[in,out] i  input stream to read a serialized JSON value from
17259
    @param[in,out] j  JSON value to write the deserialized input to
17260
17261
    @throw parse_error.101 in case of an unexpected token
17262
    @throw parse_error.102 if to_unicode fails or surrogate error
17263
    @throw parse_error.103 if to_unicode fails
17264
17265
    @complexity Linear in the length of the input. The parser is a predictive
17266
    LL(1) parser.
17267
17268
    @note A UTF-8 byte order mark is silently ignored.
17269
17270
    @liveexample{The example below shows how a JSON value is constructed by
17271
    reading a serialization from a stream.,operator_deserialize}
17272
17273
    @sa parse(std::istream&, const parser_callback_t) for a variant with a
17274
    parser callback function to filter values while parsing
17275
17276
    @since version 1.0.0
17277
    */
17278
    friend std::istream& operator>>(std::istream& i, basic_json& j)
17279
812
    {
17280
812
        parser(detail::input_adapter(i)).parse(false, j);
17281
812
        return i;
17282
812
    }
17283
17284
    /// @}
17285
17286
    ///////////////////////////
17287
    // convenience functions //
17288
    ///////////////////////////
17289
17290
    /*!
17291
    @brief return the type as string
17292
17293
    Returns the type name as string to be used in error messages - usually to
17294
    indicate that a function was called on a wrong JSON type.
17295
17296
    @return a string representation of a the @a m_type member:
17297
            Value type  | return value
17298
            ----------- | -------------
17299
            null        | `"null"`
17300
            boolean     | `"boolean"`
17301
            string      | `"string"`
17302
            number      | `"number"` (for all number types)
17303
            object      | `"object"`
17304
            array       | `"array"`
17305
            discarded   | `"discarded"`
17306
17307
    @exceptionsafety No-throw guarantee: this function never throws exceptions.
17308
17309
    @complexity Constant.
17310
17311
    @liveexample{The following code exemplifies `type_name()` for all JSON
17312
    types.,type_name}
17313
17314
    @sa @ref type() -- return the type of the JSON value
17315
    @sa @ref operator value_t() -- return the type of the JSON value (implicit)
17316
17317
    @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept`
17318
    since 3.0.0
17319
    */
17320
    const char* type_name() const noexcept
17321
0
    {
17322
0
        {
17323
0
            switch (m_type)
17324
0
            {
17325
0
                case value_t::null:
17326
0
                    return "null";
17327
0
                case value_t::object:
17328
0
                    return "object";
17329
0
                case value_t::array:
17330
0
                    return "array";
17331
0
                case value_t::string:
17332
0
                    return "string";
17333
0
                case value_t::boolean:
17334
0
                    return "boolean";
17335
0
                case value_t::discarded:
17336
0
                    return "discarded";
17337
0
                default:
17338
0
                    return "number";
17339
0
            }
17340
0
        }
17341
0
    }
17342
17343
17344
  private:
17345
    //////////////////////
17346
    // member variables //
17347
    //////////////////////
17348
17349
    /// the type of the current element
17350
    value_t m_type = value_t::null;
17351
17352
    /// the value of the current element
17353
    json_value m_value = {};
17354
17355
    //////////////////////////////////////////
17356
    // binary serialization/deserialization //
17357
    //////////////////////////////////////////
17358
17359
    /// @name binary serialization/deserialization support
17360
    /// @{
17361
17362
  public:
17363
    /*!
17364
    @brief create a CBOR serialization of a given JSON value
17365
17366
    Serializes a given JSON value @a j to a byte vector using the CBOR (Concise
17367
    Binary Object Representation) serialization format. CBOR is a binary
17368
    serialization format which aims to be more compact than JSON itself, yet
17369
    more efficient to parse.
17370
17371
    The library uses the following mapping from JSON values types to
17372
    CBOR types according to the CBOR specification (RFC 7049):
17373
17374
    JSON value type | value/range                                | CBOR type                          | first byte
17375
    --------------- | ------------------------------------------ | ---------------------------------- | ---------------
17376
    null            | `null`                                     | Null                               | 0xF6
17377
    boolean         | `true`                                     | True                               | 0xF5
17378
    boolean         | `false`                                    | False                              | 0xF4
17379
    number_integer  | -9223372036854775808..-2147483649          | Negative integer (8 bytes follow)  | 0x3B
17380
    number_integer  | -2147483648..-32769                        | Negative integer (4 bytes follow)  | 0x3A
17381
    number_integer  | -32768..-129                               | Negative integer (2 bytes follow)  | 0x39
17382
    number_integer  | -128..-25                                  | Negative integer (1 byte follow)   | 0x38
17383
    number_integer  | -24..-1                                    | Negative integer                   | 0x20..0x37
17384
    number_integer  | 0..23                                      | Integer                            | 0x00..0x17
17385
    number_integer  | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18
17386
    number_integer  | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19
17387
    number_integer  | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A
17388
    number_integer  | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B
17389
    number_unsigned | 0..23                                      | Integer                            | 0x00..0x17
17390
    number_unsigned | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18
17391
    number_unsigned | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19
17392
    number_unsigned | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A
17393
    number_unsigned | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B
17394
    number_float    | *any value*                                | Double-Precision Float             | 0xFB
17395
    string          | *length*: 0..23                            | UTF-8 string                       | 0x60..0x77
17396
    string          | *length*: 23..255                          | UTF-8 string (1 byte follow)       | 0x78
17397
    string          | *length*: 256..65535                       | UTF-8 string (2 bytes follow)      | 0x79
17398
    string          | *length*: 65536..4294967295                | UTF-8 string (4 bytes follow)      | 0x7A
17399
    string          | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow)      | 0x7B
17400
    array           | *size*: 0..23                              | array                              | 0x80..0x97
17401
    array           | *size*: 23..255                            | array (1 byte follow)              | 0x98
17402
    array           | *size*: 256..65535                         | array (2 bytes follow)             | 0x99
17403
    array           | *size*: 65536..4294967295                  | array (4 bytes follow)             | 0x9A
17404
    array           | *size*: 4294967296..18446744073709551615   | array (8 bytes follow)             | 0x9B
17405
    object          | *size*: 0..23                              | map                                | 0xA0..0xB7
17406
    object          | *size*: 23..255                            | map (1 byte follow)                | 0xB8
17407
    object          | *size*: 256..65535                         | map (2 bytes follow)               | 0xB9
17408
    object          | *size*: 65536..4294967295                  | map (4 bytes follow)               | 0xBA
17409
    object          | *size*: 4294967296..18446744073709551615   | map (8 bytes follow)               | 0xBB
17410
17411
    @note The mapping is **complete** in the sense that any JSON value type
17412
          can be converted to a CBOR value.
17413
17414
    @note If NaN or Infinity are stored inside a JSON number, they are
17415
          serialized properly. This behavior differs from the @ref dump()
17416
          function which serializes NaN or Infinity to `null`.
17417
17418
    @note The following CBOR types are not used in the conversion:
17419
          - byte strings (0x40..0x5F)
17420
          - UTF-8 strings terminated by "break" (0x7F)
17421
          - arrays terminated by "break" (0x9F)
17422
          - maps terminated by "break" (0xBF)
17423
          - date/time (0xC0..0xC1)
17424
          - bignum (0xC2..0xC3)
17425
          - decimal fraction (0xC4)
17426
          - bigfloat (0xC5)
17427
          - tagged items (0xC6..0xD4, 0xD8..0xDB)
17428
          - expected conversions (0xD5..0xD7)
17429
          - simple values (0xE0..0xF3, 0xF8)
17430
          - undefined (0xF7)
17431
          - half and single-precision floats (0xF9-0xFA)
17432
          - break (0xFF)
17433
17434
    @param[in] j  JSON value to serialize
17435
    @return MessagePack serialization as byte vector
17436
17437
    @complexity Linear in the size of the JSON value @a j.
17438
17439
    @liveexample{The example shows the serialization of a JSON value to a byte
17440
    vector in CBOR format.,to_cbor}
17441
17442
    @sa http://cbor.io
17443
    @sa @ref from_cbor(detail::input_adapter, const bool strict) for the
17444
        analogous deserialization
17445
    @sa @ref to_msgpack(const basic_json&) for the related MessagePack format
17446
    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the
17447
             related UBJSON format
17448
17449
    @since version 2.0.9
17450
    */
17451
    static std::vector<uint8_t> to_cbor(const basic_json& j)
17452
    {
17453
        std::vector<uint8_t> result;
17454
        to_cbor(j, result);
17455
        return result;
17456
    }
17457
17458
    static void to_cbor(const basic_json& j, detail::output_adapter<uint8_t> o)
17459
    {
17460
        binary_writer<uint8_t>(o).write_cbor(j);
17461
    }
17462
17463
    static void to_cbor(const basic_json& j, detail::output_adapter<char> o)
17464
    {
17465
        binary_writer<char>(o).write_cbor(j);
17466
    }
17467
17468
    /*!
17469
    @brief create a MessagePack serialization of a given JSON value
17470
17471
    Serializes a given JSON value @a j to a byte vector using the MessagePack
17472
    serialization format. MessagePack is a binary serialization format which
17473
    aims to be more compact than JSON itself, yet more efficient to parse.
17474
17475
    The library uses the following mapping from JSON values types to
17476
    MessagePack types according to the MessagePack specification:
17477
17478
    JSON value type | value/range                       | MessagePack type | first byte
17479
    --------------- | --------------------------------- | ---------------- | ----------
17480
    null            | `null`                            | nil              | 0xC0
17481
    boolean         | `true`                            | true             | 0xC3
17482
    boolean         | `false`                           | false            | 0xC2
17483
    number_integer  | -9223372036854775808..-2147483649 | int64            | 0xD3
17484
    number_integer  | -2147483648..-32769               | int32            | 0xD2
17485
    number_integer  | -32768..-129                      | int16            | 0xD1
17486
    number_integer  | -128..-33                         | int8             | 0xD0
17487
    number_integer  | -32..-1                           | negative fixint  | 0xE0..0xFF
17488
    number_integer  | 0..127                            | positive fixint  | 0x00..0x7F
17489
    number_integer  | 128..255                          | uint 8           | 0xCC
17490
    number_integer  | 256..65535                        | uint 16          | 0xCD
17491
    number_integer  | 65536..4294967295                 | uint 32          | 0xCE
17492
    number_integer  | 4294967296..18446744073709551615  | uint 64          | 0xCF
17493
    number_unsigned | 0..127                            | positive fixint  | 0x00..0x7F
17494
    number_unsigned | 128..255                          | uint 8           | 0xCC
17495
    number_unsigned | 256..65535                        | uint 16          | 0xCD
17496
    number_unsigned | 65536..4294967295                 | uint 32          | 0xCE
17497
    number_unsigned | 4294967296..18446744073709551615  | uint 64          | 0xCF
17498
    number_float    | *any value*                       | float 64         | 0xCB
17499
    string          | *length*: 0..31                   | fixstr           | 0xA0..0xBF
17500
    string          | *length*: 32..255                 | str 8            | 0xD9
17501
    string          | *length*: 256..65535              | str 16           | 0xDA
17502
    string          | *length*: 65536..4294967295       | str 32           | 0xDB
17503
    array           | *size*: 0..15                     | fixarray         | 0x90..0x9F
17504
    array           | *size*: 16..65535                 | array 16         | 0xDC
17505
    array           | *size*: 65536..4294967295         | array 32         | 0xDD
17506
    object          | *size*: 0..15                     | fix map          | 0x80..0x8F
17507
    object          | *size*: 16..65535                 | map 16           | 0xDE
17508
    object          | *size*: 65536..4294967295         | map 32           | 0xDF
17509
17510
    @note The mapping is **complete** in the sense that any JSON value type
17511
          can be converted to a MessagePack value.
17512
17513
    @note The following values can **not** be converted to a MessagePack value:
17514
          - strings with more than 4294967295 bytes
17515
          - arrays with more than 4294967295 elements
17516
          - objects with more than 4294967295 elements
17517
17518
    @note The following MessagePack types are not used in the conversion:
17519
          - bin 8 - bin 32 (0xC4..0xC6)
17520
          - ext 8 - ext 32 (0xC7..0xC9)
17521
          - float 32 (0xCA)
17522
          - fixext 1 - fixext 16 (0xD4..0xD8)
17523
17524
    @note Any MessagePack output created @ref to_msgpack can be successfully
17525
          parsed by @ref from_msgpack.
17526
17527
    @note If NaN or Infinity are stored inside a JSON number, they are
17528
          serialized properly. This behavior differs from the @ref dump()
17529
          function which serializes NaN or Infinity to `null`.
17530
17531
    @param[in] j  JSON value to serialize
17532
    @return MessagePack serialization as byte vector
17533
17534
    @complexity Linear in the size of the JSON value @a j.
17535
17536
    @liveexample{The example shows the serialization of a JSON value to a byte
17537
    vector in MessagePack format.,to_msgpack}
17538
17539
    @sa http://msgpack.org
17540
    @sa @ref from_msgpack(const std::vector<uint8_t>&, const size_t) for the
17541
        analogous deserialization
17542
    @sa @ref to_cbor(const basic_json& for the related CBOR format
17543
    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the
17544
             related UBJSON format
17545
17546
    @since version 2.0.9
17547
    */
17548
    static std::vector<uint8_t> to_msgpack(const basic_json& j)
17549
    {
17550
        std::vector<uint8_t> result;
17551
        to_msgpack(j, result);
17552
        return result;
17553
    }
17554
17555
    static void to_msgpack(const basic_json& j, detail::output_adapter<uint8_t> o)
17556
    {
17557
        binary_writer<uint8_t>(o).write_msgpack(j);
17558
    }
17559
17560
    static void to_msgpack(const basic_json& j, detail::output_adapter<char> o)
17561
    {
17562
        binary_writer<char>(o).write_msgpack(j);
17563
    }
17564
17565
    /*!
17566
    @brief create a UBJSON serialization of a given JSON value
17567
17568
    Serializes a given JSON value @a j to a byte vector using the UBJSON
17569
    (Universal Binary JSON) serialization format. UBJSON aims to be more compact
17570
    than JSON itself, yet more efficient to parse.
17571
17572
    The library uses the following mapping from JSON values types to
17573
    UBJSON types according to the UBJSON specification:
17574
17575
    JSON value type | value/range                       | UBJSON type | marker
17576
    --------------- | --------------------------------- | ----------- | ------
17577
    null            | `null`                            | null        | `Z`
17578
    boolean         | `true`                            | true        | `T`
17579
    boolean         | `false`                           | false       | `F`
17580
    number_integer  | -9223372036854775808..-2147483649 | int64       | `L`
17581
    number_integer  | -2147483648..-32769               | int32       | `l`
17582
    number_integer  | -32768..-129                      | int16       | `I`
17583
    number_integer  | -128..127                         | int8        | `i`
17584
    number_integer  | 128..255                          | uint8       | `U`
17585
    number_integer  | 256..32767                        | int16       | `I`
17586
    number_integer  | 32768..2147483647                 | int32       | `l`
17587
    number_integer  | 2147483648..9223372036854775807   | int64       | `L`
17588
    number_unsigned | 0..127                            | int8        | `i`
17589
    number_unsigned | 128..255                          | uint8       | `U`
17590
    number_unsigned | 256..32767                        | int16       | `I`
17591
    number_unsigned | 32768..2147483647                 | int32       | `l`
17592
    number_unsigned | 2147483648..9223372036854775807   | int64       | `L`
17593
    number_float    | *any value*                       | float64     | `D`
17594
    string          | *with shortest length indicator*  | string      | `S`
17595
    array           | *see notes on optimized format*   | array       | `[`
17596
    object          | *see notes on optimized format*   | map         | `{`
17597
17598
    @note The mapping is **complete** in the sense that any JSON value type
17599
          can be converted to a UBJSON value.
17600
17601
    @note The following values can **not** be converted to a UBJSON value:
17602
          - strings with more than 9223372036854775807 bytes (theoretical)
17603
          - unsigned integer numbers above 9223372036854775807
17604
17605
    @note The following markers are not used in the conversion:
17606
          - `Z`: no-op values are not created.
17607
          - `C`: single-byte strings are serialized with `S` markers.
17608
17609
    @note Any UBJSON output created @ref to_ubjson can be successfully parsed
17610
          by @ref from_ubjson.
17611
17612
    @note If NaN or Infinity are stored inside a JSON number, they are
17613
          serialized properly. This behavior differs from the @ref dump()
17614
          function which serializes NaN or Infinity to `null`.
17615
17616
    @note The optimized formats for containers are supported: Parameter
17617
          @a use_size adds size information to the beginning of a container and
17618
          removes the closing marker. Parameter @a use_type further checks
17619
          whether all elements of a container have the same type and adds the
17620
          type marker to the beginning of the container. The @a use_type
17621
          parameter must only be used together with @a use_size = true. Note
17622
          that @a use_size = true alone may result in larger representations -
17623
          the benefit of this parameter is that the receiving side is
17624
          immediately informed on the number of elements of the container.
17625
17626
    @param[in] j  JSON value to serialize
17627
    @param[in] use_size  whether to add size annotations to container types
17628
    @param[in] use_type  whether to add type annotations to container types
17629
                         (must be combined with @a use_size = true)
17630
    @return UBJSON serialization as byte vector
17631
17632
    @complexity Linear in the size of the JSON value @a j.
17633
17634
    @liveexample{The example shows the serialization of a JSON value to a byte
17635
    vector in UBJSON format.,to_ubjson}
17636
17637
    @sa http://ubjson.org
17638
    @sa @ref from_ubjson(detail::input_adapter, const bool strict) for the
17639
        analogous deserialization
17640
    @sa @ref to_cbor(const basic_json& for the related CBOR format
17641
    @sa @ref to_msgpack(const basic_json&) for the related MessagePack format
17642
17643
    @since version 3.1.0
17644
    */
17645
    static std::vector<uint8_t> to_ubjson(const basic_json& j,
17646
                                          const bool use_size = false,
17647
                                          const bool use_type = false)
17648
    {
17649
        std::vector<uint8_t> result;
17650
        to_ubjson(j, result, use_size, use_type);
17651
        return result;
17652
    }
17653
17654
    static void to_ubjson(const basic_json& j, detail::output_adapter<uint8_t> o,
17655
                          const bool use_size = false, const bool use_type = false)
17656
    {
17657
        binary_writer<uint8_t>(o).write_ubjson(j, use_size, use_type);
17658
    }
17659
17660
    static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,
17661
                          const bool use_size = false, const bool use_type = false)
17662
    {
17663
        binary_writer<char>(o).write_ubjson(j, use_size, use_type);
17664
    }
17665
17666
    /*!
17667
    @brief create a JSON value from an input in CBOR format
17668
17669
    Deserializes a given input @a i to a JSON value using the CBOR (Concise
17670
    Binary Object Representation) serialization format.
17671
17672
    The library maps CBOR types to JSON value types as follows:
17673
17674
    CBOR type              | JSON value type | first byte
17675
    ---------------------- | --------------- | ----------
17676
    Integer                | number_unsigned | 0x00..0x17
17677
    Unsigned integer       | number_unsigned | 0x18
17678
    Unsigned integer       | number_unsigned | 0x19
17679
    Unsigned integer       | number_unsigned | 0x1A
17680
    Unsigned integer       | number_unsigned | 0x1B
17681
    Negative integer       | number_integer  | 0x20..0x37
17682
    Negative integer       | number_integer  | 0x38
17683
    Negative integer       | number_integer  | 0x39
17684
    Negative integer       | number_integer  | 0x3A
17685
    Negative integer       | number_integer  | 0x3B
17686
    Negative integer       | number_integer  | 0x40..0x57
17687
    UTF-8 string           | string          | 0x60..0x77
17688
    UTF-8 string           | string          | 0x78
17689
    UTF-8 string           | string          | 0x79
17690
    UTF-8 string           | string          | 0x7A
17691
    UTF-8 string           | string          | 0x7B
17692
    UTF-8 string           | string          | 0x7F
17693
    array                  | array           | 0x80..0x97
17694
    array                  | array           | 0x98
17695
    array                  | array           | 0x99
17696
    array                  | array           | 0x9A
17697
    array                  | array           | 0x9B
17698
    array                  | array           | 0x9F
17699
    map                    | object          | 0xA0..0xB7
17700
    map                    | object          | 0xB8
17701
    map                    | object          | 0xB9
17702
    map                    | object          | 0xBA
17703
    map                    | object          | 0xBB
17704
    map                    | object          | 0xBF
17705
    False                  | `false`         | 0xF4
17706
    True                   | `true`          | 0xF5
17707
    Nill                   | `null`          | 0xF6
17708
    Half-Precision Float   | number_float    | 0xF9
17709
    Single-Precision Float | number_float    | 0xFA
17710
    Double-Precision Float | number_float    | 0xFB
17711
17712
    @warning The mapping is **incomplete** in the sense that not all CBOR
17713
             types can be converted to a JSON value. The following CBOR types
17714
             are not supported and will yield parse errors (parse_error.112):
17715
             - byte strings (0x40..0x5F)
17716
             - date/time (0xC0..0xC1)
17717
             - bignum (0xC2..0xC3)
17718
             - decimal fraction (0xC4)
17719
             - bigfloat (0xC5)
17720
             - tagged items (0xC6..0xD4, 0xD8..0xDB)
17721
             - expected conversions (0xD5..0xD7)
17722
             - simple values (0xE0..0xF3, 0xF8)
17723
             - undefined (0xF7)
17724
17725
    @warning CBOR allows map keys of any type, whereas JSON only allows
17726
             strings as keys in object values. Therefore, CBOR maps with keys
17727
             other than UTF-8 strings are rejected (parse_error.113).
17728
17729
    @note Any CBOR output created @ref to_cbor can be successfully parsed by
17730
          @ref from_cbor.
17731
17732
    @param[in] i  an input in CBOR format convertible to an input adapter
17733
    @param[in] strict  whether to expect the input to be consumed until EOF
17734
                       (true by default)
17735
    @param[in] allow_exceptions  whether to throw exceptions in case of a
17736
    parse error (optional, true by default)
17737
17738
    @return deserialized JSON value
17739
17740
    @throw parse_error.110 if the given input ends prematurely or the end of
17741
    file was not reached when @a strict was set to true
17742
    @throw parse_error.112 if unsupported features from CBOR were
17743
    used in the given input @a v or if the input is not valid CBOR
17744
    @throw parse_error.113 if a string was expected as map key, but not found
17745
17746
    @complexity Linear in the size of the input @a i.
17747
17748
    @liveexample{The example shows the deserialization of a byte vector in CBOR
17749
    format to a JSON value.,from_cbor}
17750
17751
    @sa http://cbor.io
17752
    @sa @ref to_cbor(const basic_json&) for the analogous serialization
17753
    @sa @ref from_msgpack(detail::input_adapter, const bool, const bool) for the
17754
        related MessagePack format
17755
    @sa @ref from_ubjson(detail::input_adapter, const bool, const bool) for the
17756
        related UBJSON format
17757
17758
    @since version 2.0.9; parameter @a start_index since 2.1.1; changed to
17759
           consume input adapters, removed start_index parameter, and added
17760
           @a strict parameter since 3.0.0; added @allow_exceptions parameter
17761
           since 3.2.0
17762
    */
17763
    static basic_json from_cbor(detail::input_adapter&& i,
17764
                                const bool strict = true,
17765
                                const bool allow_exceptions = true)
17766
    {
17767
        basic_json result;
17768
        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
17769
        const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::cbor, &sdp, strict);
17770
        return res ? result : basic_json(value_t::discarded);
17771
    }
17772
17773
    /*!
17774
    @copydoc from_cbor(detail::input_adapter, const bool, const bool)
17775
    */
17776
    template<typename A1, typename A2,
17777
             detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>
17778
    static basic_json from_cbor(A1 && a1, A2 && a2,
17779
                                const bool strict = true,
17780
                                const bool allow_exceptions = true)
17781
    {
17782
        basic_json result;
17783
        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
17784
        const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::cbor, &sdp, strict);
17785
        return res ? result : basic_json(value_t::discarded);
17786
    }
17787
17788
    /*!
17789
    @brief create a JSON value from an input in MessagePack format
17790
17791
    Deserializes a given input @a i to a JSON value using the MessagePack
17792
    serialization format.
17793
17794
    The library maps MessagePack types to JSON value types as follows:
17795
17796
    MessagePack type | JSON value type | first byte
17797
    ---------------- | --------------- | ----------
17798
    positive fixint  | number_unsigned | 0x00..0x7F
17799
    fixmap           | object          | 0x80..0x8F
17800
    fixarray         | array           | 0x90..0x9F
17801
    fixstr           | string          | 0xA0..0xBF
17802
    nil              | `null`          | 0xC0
17803
    false            | `false`         | 0xC2
17804
    true             | `true`          | 0xC3
17805
    float 32         | number_float    | 0xCA
17806
    float 64         | number_float    | 0xCB
17807
    uint 8           | number_unsigned | 0xCC
17808
    uint 16          | number_unsigned | 0xCD
17809
    uint 32          | number_unsigned | 0xCE
17810
    uint 64          | number_unsigned | 0xCF
17811
    int 8            | number_integer  | 0xD0
17812
    int 16           | number_integer  | 0xD1
17813
    int 32           | number_integer  | 0xD2
17814
    int 64           | number_integer  | 0xD3
17815
    str 8            | string          | 0xD9
17816
    str 16           | string          | 0xDA
17817
    str 32           | string          | 0xDB
17818
    array 16         | array           | 0xDC
17819
    array 32         | array           | 0xDD
17820
    map 16           | object          | 0xDE
17821
    map 32           | object          | 0xDF
17822
    negative fixint  | number_integer  | 0xE0-0xFF
17823
17824
    @warning The mapping is **incomplete** in the sense that not all
17825
             MessagePack types can be converted to a JSON value. The following
17826
             MessagePack types are not supported and will yield parse errors:
17827
              - bin 8 - bin 32 (0xC4..0xC6)
17828
              - ext 8 - ext 32 (0xC7..0xC9)
17829
              - fixext 1 - fixext 16 (0xD4..0xD8)
17830
17831
    @note Any MessagePack output created @ref to_msgpack can be successfully
17832
          parsed by @ref from_msgpack.
17833
17834
    @param[in] i  an input in MessagePack format convertible to an input
17835
                  adapter
17836
    @param[in] strict  whether to expect the input to be consumed until EOF
17837
                       (true by default)
17838
    @param[in] allow_exceptions  whether to throw exceptions in case of a
17839
    parse error (optional, true by default)
17840
17841
    @return deserialized JSON value
17842
17843
    @throw parse_error.110 if the given input ends prematurely or the end of
17844
    file was not reached when @a strict was set to true
17845
    @throw parse_error.112 if unsupported features from MessagePack were
17846
    used in the given input @a i or if the input is not valid MessagePack
17847
    @throw parse_error.113 if a string was expected as map key, but not found
17848
17849
    @complexity Linear in the size of the input @a i.
17850
17851
    @liveexample{The example shows the deserialization of a byte vector in
17852
    MessagePack format to a JSON value.,from_msgpack}
17853
17854
    @sa http://msgpack.org
17855
    @sa @ref to_msgpack(const basic_json&) for the analogous serialization
17856
    @sa @ref from_cbor(detail::input_adapter, const bool, const bool) for the
17857
        related CBOR format
17858
    @sa @ref from_ubjson(detail::input_adapter, const bool, const bool) for
17859
        the related UBJSON format
17860
17861
    @since version 2.0.9; parameter @a start_index since 2.1.1; changed to
17862
           consume input adapters, removed start_index parameter, and added
17863
           @a strict parameter since 3.0.0; added @allow_exceptions parameter
17864
           since 3.2.0
17865
    */
17866
    static basic_json from_msgpack(detail::input_adapter&& i,
17867
                                   const bool strict = true,
17868
                                   const bool allow_exceptions = true)
17869
    {
17870
        basic_json result;
17871
        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
17872
        const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::msgpack, &sdp, strict);
17873
        return res ? result : basic_json(value_t::discarded);
17874
    }
17875
17876
    /*!
17877
    @copydoc from_msgpack(detail::input_adapter, const bool, const bool)
17878
    */
17879
    template<typename A1, typename A2,
17880
             detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>
17881
    static basic_json from_msgpack(A1 && a1, A2 && a2,
17882
                                   const bool strict = true,
17883
                                   const bool allow_exceptions = true)
17884
    {
17885
        basic_json result;
17886
        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
17887
        const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::msgpack, &sdp, strict);
17888
        return res ? result : basic_json(value_t::discarded);
17889
    }
17890
17891
    /*!
17892
    @brief create a JSON value from an input in UBJSON format
17893
17894
    Deserializes a given input @a i to a JSON value using the UBJSON (Universal
17895
    Binary JSON) serialization format.
17896
17897
    The library maps UBJSON types to JSON value types as follows:
17898
17899
    UBJSON type | JSON value type                         | marker
17900
    ----------- | --------------------------------------- | ------
17901
    no-op       | *no value, next value is read*          | `N`
17902
    null        | `null`                                  | `Z`
17903
    false       | `false`                                 | `F`
17904
    true        | `true`                                  | `T`
17905
    float32     | number_float                            | `d`
17906
    float64     | number_float                            | `D`
17907
    uint8       | number_unsigned                         | `U`
17908
    int8        | number_integer                          | `i`
17909
    int16       | number_integer                          | `I`
17910
    int32       | number_integer                          | `l`
17911
    int64       | number_integer                          | `L`
17912
    string      | string                                  | `S`
17913
    char        | string                                  | `C`
17914
    array       | array (optimized values are supported)  | `[`
17915
    object      | object (optimized values are supported) | `{`
17916
17917
    @note The mapping is **complete** in the sense that any UBJSON value can
17918
          be converted to a JSON value.
17919
17920
    @param[in] i  an input in UBJSON format convertible to an input adapter
17921
    @param[in] strict  whether to expect the input to be consumed until EOF
17922
                       (true by default)
17923
    @param[in] allow_exceptions  whether to throw exceptions in case of a
17924
    parse error (optional, true by default)
17925
17926
    @return deserialized JSON value
17927
17928
    @throw parse_error.110 if the given input ends prematurely or the end of
17929
    file was not reached when @a strict was set to true
17930
    @throw parse_error.112 if a parse error occurs
17931
    @throw parse_error.113 if a string could not be parsed successfully
17932
17933
    @complexity Linear in the size of the input @a i.
17934
17935
    @liveexample{The example shows the deserialization of a byte vector in
17936
    UBJSON format to a JSON value.,from_ubjson}
17937
17938
    @sa http://ubjson.org
17939
    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the
17940
             analogous serialization
17941
    @sa @ref from_cbor(detail::input_adapter, const bool, const bool) for the
17942
        related CBOR format
17943
    @sa @ref from_msgpack(detail::input_adapter, const bool, const bool) for
17944
        the related MessagePack format
17945
17946
    @since version 3.1.0; added @allow_exceptions parameter since 3.2.0
17947
    */
17948
    static basic_json from_ubjson(detail::input_adapter&& i,
17949
                                  const bool strict = true,
17950
                                  const bool allow_exceptions = true)
17951
    {
17952
        basic_json result;
17953
        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
17954
        const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::ubjson, &sdp, strict);
17955
        return res ? result : basic_json(value_t::discarded);
17956
    }
17957
17958
    /*!
17959
    @copydoc from_ubjson(detail::input_adapter, const bool, const bool)
17960
    */
17961
    template<typename A1, typename A2,
17962
             detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>
17963
    static basic_json from_ubjson(A1 && a1, A2 && a2,
17964
                                  const bool strict = true,
17965
                                  const bool allow_exceptions = true)
17966
    {
17967
        basic_json result;
17968
        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
17969
        const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::ubjson, &sdp, strict);
17970
        return res ? result : basic_json(value_t::discarded);
17971
    }
17972
17973
    /// @}
17974
17975
    //////////////////////////
17976
    // JSON Pointer support //
17977
    //////////////////////////
17978
17979
    /// @name JSON Pointer functions
17980
    /// @{
17981
17982
    /*!
17983
    @brief access specified element via JSON Pointer
17984
17985
    Uses a JSON pointer to retrieve a reference to the respective JSON value.
17986
    No bound checking is performed. Similar to @ref operator[](const typename
17987
    object_t::key_type&), `null` values are created in arrays and objects if
17988
    necessary.
17989
17990
    In particular:
17991
    - If the JSON pointer points to an object key that does not exist, it
17992
      is created an filled with a `null` value before a reference to it
17993
      is returned.
17994
    - If the JSON pointer points to an array index that does not exist, it
17995
      is created an filled with a `null` value before a reference to it
17996
      is returned. All indices between the current maximum and the given
17997
      index are also filled with `null`.
17998
    - The special value `-` is treated as a synonym for the index past the
17999
      end.
18000
18001
    @param[in] ptr  a JSON pointer
18002
18003
    @return reference to the element pointed to by @a ptr
18004
18005
    @complexity Constant.
18006
18007
    @throw parse_error.106   if an array index begins with '0'
18008
    @throw parse_error.109   if an array index was not a number
18009
    @throw out_of_range.404  if the JSON pointer can not be resolved
18010
18011
    @liveexample{The behavior is shown in the example.,operatorjson_pointer}
18012
18013
    @since version 2.0.0
18014
    */
18015
    reference operator[](const json_pointer& ptr)
18016
    {
18017
        return ptr.get_unchecked(this);
18018
    }
18019
18020
    /*!
18021
    @brief access specified element via JSON Pointer
18022
18023
    Uses a JSON pointer to retrieve a reference to the respective JSON value.
18024
    No bound checking is performed. The function does not change the JSON
18025
    value; no `null` values are created. In particular, the the special value
18026
    `-` yields an exception.
18027
18028
    @param[in] ptr  JSON pointer to the desired element
18029
18030
    @return const reference to the element pointed to by @a ptr
18031
18032
    @complexity Constant.
18033
18034
    @throw parse_error.106   if an array index begins with '0'
18035
    @throw parse_error.109   if an array index was not a number
18036
    @throw out_of_range.402  if the array index '-' is used
18037
    @throw out_of_range.404  if the JSON pointer can not be resolved
18038
18039
    @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}
18040
18041
    @since version 2.0.0
18042
    */
18043
    const_reference operator[](const json_pointer& ptr) const
18044
    {
18045
        return ptr.get_unchecked(this);
18046
    }
18047
18048
    /*!
18049
    @brief access specified element via JSON Pointer
18050
18051
    Returns a reference to the element at with specified JSON pointer @a ptr,
18052
    with bounds checking.
18053
18054
    @param[in] ptr  JSON pointer to the desired element
18055
18056
    @return reference to the element pointed to by @a ptr
18057
18058
    @throw parse_error.106 if an array index in the passed JSON pointer @a ptr
18059
    begins with '0'. See example below.
18060
18061
    @throw parse_error.109 if an array index in the passed JSON pointer @a ptr
18062
    is not a number. See example below.
18063
18064
    @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr
18065
    is out of range. See example below.
18066
18067
    @throw out_of_range.402 if the array index '-' is used in the passed JSON
18068
    pointer @a ptr. As `at` provides checked access (and no elements are
18069
    implicitly inserted), the index '-' is always invalid. See example below.
18070
18071
    @throw out_of_range.403 if the JSON pointer describes a key of an object
18072
    which cannot be found. See example below.
18073
18074
    @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.
18075
    See example below.
18076
18077
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
18078
    changes in the JSON value.
18079
18080
    @complexity Constant.
18081
18082
    @since version 2.0.0
18083
18084
    @liveexample{The behavior is shown in the example.,at_json_pointer}
18085
    */
18086
    reference at(const json_pointer& ptr)
18087
    {
18088
        return ptr.get_checked(this);
18089
    }
18090
18091
    /*!
18092
    @brief access specified element via JSON Pointer
18093
18094
    Returns a const reference to the element at with specified JSON pointer @a
18095
    ptr, with bounds checking.
18096
18097
    @param[in] ptr  JSON pointer to the desired element
18098
18099
    @return reference to the element pointed to by @a ptr
18100
18101
    @throw parse_error.106 if an array index in the passed JSON pointer @a ptr
18102
    begins with '0'. See example below.
18103
18104
    @throw parse_error.109 if an array index in the passed JSON pointer @a ptr
18105
    is not a number. See example below.
18106
18107
    @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr
18108
    is out of range. See example below.
18109
18110
    @throw out_of_range.402 if the array index '-' is used in the passed JSON
18111
    pointer @a ptr. As `at` provides checked access (and no elements are
18112
    implicitly inserted), the index '-' is always invalid. See example below.
18113
18114
    @throw out_of_range.403 if the JSON pointer describes a key of an object
18115
    which cannot be found. See example below.
18116
18117
    @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.
18118
    See example below.
18119
18120
    @exceptionsafety Strong guarantee: if an exception is thrown, there are no
18121
    changes in the JSON value.
18122
18123
    @complexity Constant.
18124
18125
    @since version 2.0.0
18126
18127
    @liveexample{The behavior is shown in the example.,at_json_pointer_const}
18128
    */
18129
    const_reference at(const json_pointer& ptr) const
18130
    {
18131
        return ptr.get_checked(this);
18132
    }
18133
18134
    /*!
18135
    @brief return flattened JSON value
18136
18137
    The function creates a JSON object whose keys are JSON pointers (see [RFC
18138
    6901](https://tools.ietf.org/html/rfc6901)) and whose values are all
18139
    primitive. The original JSON value can be restored using the @ref
18140
    unflatten() function.
18141
18142
    @return an object that maps JSON pointers to primitive values
18143
18144
    @note Empty objects and arrays are flattened to `null` and will not be
18145
          reconstructed correctly by the @ref unflatten() function.
18146
18147
    @complexity Linear in the size the JSON value.
18148
18149
    @liveexample{The following code shows how a JSON object is flattened to an
18150
    object whose keys consist of JSON pointers.,flatten}
18151
18152
    @sa @ref unflatten() for the reverse function
18153
18154
    @since version 2.0.0
18155
    */
18156
    basic_json flatten() const
18157
    {
18158
        basic_json result(value_t::object);
18159
        json_pointer::flatten("", *this, result);
18160
        return result;
18161
    }
18162
18163
    /*!
18164
    @brief unflatten a previously flattened JSON value
18165
18166
    The function restores the arbitrary nesting of a JSON value that has been
18167
    flattened before using the @ref flatten() function. The JSON value must
18168
    meet certain constraints:
18169
    1. The value must be an object.
18170
    2. The keys must be JSON pointers (see
18171
       [RFC 6901](https://tools.ietf.org/html/rfc6901))
18172
    3. The mapped values must be primitive JSON types.
18173
18174
    @return the original JSON from a flattened version
18175
18176
    @note Empty objects and arrays are flattened by @ref flatten() to `null`
18177
          values and can not unflattened to their original type. Apart from
18178
          this example, for a JSON value `j`, the following is always true:
18179
          `j == j.flatten().unflatten()`.
18180
18181
    @complexity Linear in the size the JSON value.
18182
18183
    @throw type_error.314  if value is not an object
18184
    @throw type_error.315  if object values are not primitive
18185
18186
    @liveexample{The following code shows how a flattened JSON object is
18187
    unflattened into the original nested JSON object.,unflatten}
18188
18189
    @sa @ref flatten() for the reverse function
18190
18191
    @since version 2.0.0
18192
    */
18193
    basic_json unflatten() const
18194
    {
18195
        return json_pointer::unflatten(*this);
18196
    }
18197
18198
    /// @}
18199
18200
    //////////////////////////
18201
    // JSON Patch functions //
18202
    //////////////////////////
18203
18204
    /// @name JSON Patch functions
18205
    /// @{
18206
18207
    /*!
18208
    @brief applies a JSON patch
18209
18210
    [JSON Patch](http://jsonpatch.com) defines a JSON document structure for
18211
    expressing a sequence of operations to apply to a JSON) document. With
18212
    this function, a JSON Patch is applied to the current JSON value by
18213
    executing all operations from the patch.
18214
18215
    @param[in] json_patch  JSON patch document
18216
    @return patched document
18217
18218
    @note The application of a patch is atomic: Either all operations succeed
18219
          and the patched document is returned or an exception is thrown. In
18220
          any case, the original value is not changed: the patch is applied
18221
          to a copy of the value.
18222
18223
    @throw parse_error.104 if the JSON patch does not consist of an array of
18224
    objects
18225
18226
    @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory
18227
    attributes are missing); example: `"operation add must have member path"`
18228
18229
    @throw out_of_range.401 if an array index is out of range.
18230
18231
    @throw out_of_range.403 if a JSON pointer inside the patch could not be
18232
    resolved successfully in the current JSON value; example: `"key baz not
18233
    found"`
18234
18235
    @throw out_of_range.405 if JSON pointer has no parent ("add", "remove",
18236
    "move")
18237
18238
    @throw other_error.501 if "test" operation was unsuccessful
18239
18240
    @complexity Linear in the size of the JSON value and the length of the
18241
    JSON patch. As usually only a fraction of the JSON value is affected by
18242
    the patch, the complexity can usually be neglected.
18243
18244
    @liveexample{The following code shows how a JSON patch is applied to a
18245
    value.,patch}
18246
18247
    @sa @ref diff -- create a JSON patch by comparing two JSON values
18248
18249
    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
18250
    @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)
18251
18252
    @since version 2.0.0
18253
    */
18254
    basic_json patch(const basic_json& json_patch) const
18255
    {
18256
        // make a working copy to apply the patch to
18257
        basic_json result = *this;
18258
18259
        // the valid JSON Patch operations
18260
        enum class patch_operations {add, remove, replace, move, copy, test, invalid};
18261
18262
        const auto get_op = [](const std::string & op)
18263
        {
18264
            if (op == "add")
18265
            {
18266
                return patch_operations::add;
18267
            }
18268
            if (op == "remove")
18269
            {
18270
                return patch_operations::remove;
18271
            }
18272
            if (op == "replace")
18273
            {
18274
                return patch_operations::replace;
18275
            }
18276
            if (op == "move")
18277
            {
18278
                return patch_operations::move;
18279
            }
18280
            if (op == "copy")
18281
            {
18282
                return patch_operations::copy;
18283
            }
18284
            if (op == "test")
18285
            {
18286
                return patch_operations::test;
18287
            }
18288
18289
            return patch_operations::invalid;
18290
        };
18291
18292
        // wrapper for "add" operation; add value at ptr
18293
        const auto operation_add = [&result](json_pointer & ptr, basic_json val)
18294
        {
18295
            // adding to the root of the target document means replacing it
18296
            if (ptr.is_root())
18297
            {
18298
                result = val;
18299
            }
18300
            else
18301
            {
18302
                // make sure the top element of the pointer exists
18303
                json_pointer top_pointer = ptr.top();
18304
                if (top_pointer != ptr)
18305
                {
18306
                    result.at(top_pointer);
18307
                }
18308
18309
                // get reference to parent of JSON pointer ptr
18310
                const auto last_path = ptr.pop_back();
18311
                basic_json& parent = result[ptr];
18312
18313
                switch (parent.m_type)
18314
                {
18315
                    case value_t::null:
18316
                    case value_t::object:
18317
                    {
18318
                        // use operator[] to add value
18319
                        parent[last_path] = val;
18320
                        break;
18321
                    }
18322
18323
                    case value_t::array:
18324
                    {
18325
                        if (last_path == "-")
18326
                        {
18327
                            // special case: append to back
18328
                            parent.push_back(val);
18329
                        }
18330
                        else
18331
                        {
18332
                            const auto idx = json_pointer::array_index(last_path);
18333
                            if (JSON_UNLIKELY(static_cast<size_type>(idx) > parent.size()))
18334
                            {
18335
                                // avoid undefined behavior
18336
                                JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
18337
                            }
18338
                            else
18339
                            {
18340
                                // default case: insert add offset
18341
                                parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
18342
                            }
18343
                        }
18344
                        break;
18345
                    }
18346
18347
                    // LCOV_EXCL_START
18348
                    default:
18349
                    {
18350
                        // if there exists a parent it cannot be primitive
18351
                        assert(false);
18352
                    }
18353
                        // LCOV_EXCL_STOP
18354
                }
18355
            }
18356
        };
18357
18358
        // wrapper for "remove" operation; remove value at ptr
18359
        const auto operation_remove = [&result](json_pointer & ptr)
18360
        {
18361
            // get reference to parent of JSON pointer ptr
18362
            const auto last_path = ptr.pop_back();
18363
            basic_json& parent = result.at(ptr);
18364
18365
            // remove child
18366
            if (parent.is_object())
18367
            {
18368
                // perform range check
18369
                auto it = parent.find(last_path);
18370
                if (JSON_LIKELY(it != parent.end()))
18371
                {
18372
                    parent.erase(it);
18373
                }
18374
                else
18375
                {
18376
                    JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found"));
18377
                }
18378
            }
18379
            else if (parent.is_array())
18380
            {
18381
                // note erase performs range check
18382
                parent.erase(static_cast<size_type>(json_pointer::array_index(last_path)));
18383
            }
18384
        };
18385
18386
        // type check: top level value must be an array
18387
        if (JSON_UNLIKELY(not json_patch.is_array()))
18388
        {
18389
            JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
18390
        }
18391
18392
        // iterate and apply the operations
18393
        for (const auto& val : json_patch)
18394
        {
18395
            // wrapper to get a value for an operation
18396
            const auto get_value = [&val](const std::string & op,
18397
                                          const std::string & member,
18398
                                          bool string_type) -> basic_json &
18399
            {
18400
                // find value
18401
                auto it = val.m_value.object->find(member);
18402
18403
                // context-sensitive error message
18404
                const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'";
18405
18406
                // check if desired value is present
18407
                if (JSON_UNLIKELY(it == val.m_value.object->end()))
18408
                {
18409
                    JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'"));
18410
                }
18411
18412
                // check if result is of type string
18413
                if (JSON_UNLIKELY(string_type and not it->second.is_string()))
18414
                {
18415
                    JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'"));
18416
                }
18417
18418
                // no error: return value
18419
                return it->second;
18420
            };
18421
18422
            // type check: every element of the array must be an object
18423
            if (JSON_UNLIKELY(not val.is_object()))
18424
            {
18425
                JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
18426
            }
18427
18428
            // collect mandatory members
18429
            const std::string op = get_value("op", "op", true);
18430
            const std::string path = get_value(op, "path", true);
18431
            json_pointer ptr(path);
18432
18433
            switch (get_op(op))
18434
            {
18435
                case patch_operations::add:
18436
                {
18437
                    operation_add(ptr, get_value("add", "value", false));
18438
                    break;
18439
                }
18440
18441
                case patch_operations::remove:
18442
                {
18443
                    operation_remove(ptr);
18444
                    break;
18445
                }
18446
18447
                case patch_operations::replace:
18448
                {
18449
                    // the "path" location must exist - use at()
18450
                    result.at(ptr) = get_value("replace", "value", false);
18451
                    break;
18452
                }
18453
18454
                case patch_operations::move:
18455
                {
18456
                    const std::string from_path = get_value("move", "from", true);
18457
                    json_pointer from_ptr(from_path);
18458
18459
                    // the "from" location must exist - use at()
18460
                    basic_json v = result.at(from_ptr);
18461
18462
                    // The move operation is functionally identical to a
18463
                    // "remove" operation on the "from" location, followed
18464
                    // immediately by an "add" operation at the target
18465
                    // location with the value that was just removed.
18466
                    operation_remove(from_ptr);
18467
                    operation_add(ptr, v);
18468
                    break;
18469
                }
18470
18471
                case patch_operations::copy:
18472
                {
18473
                    const std::string from_path = get_value("copy", "from", true);
18474
                    const json_pointer from_ptr(from_path);
18475
18476
                    // the "from" location must exist - use at()
18477
                    basic_json v = result.at(from_ptr);
18478
18479
                    // The copy is functionally identical to an "add"
18480
                    // operation at the target location using the value
18481
                    // specified in the "from" member.
18482
                    operation_add(ptr, v);
18483
                    break;
18484
                }
18485
18486
                case patch_operations::test:
18487
                {
18488
                    bool success = false;
18489
                    JSON_TRY
18490
                    {
18491
                        // check if "value" matches the one at "path"
18492
                        // the "path" location must exist - use at()
18493
                        success = (result.at(ptr) == get_value("test", "value", false));
18494
                    }
18495
                    JSON_INTERNAL_CATCH (out_of_range&)
18496
                    {
18497
                        // ignore out of range errors: success remains false
18498
                    }
18499
18500
                    // throw an exception if test fails
18501
                    if (JSON_UNLIKELY(not success))
18502
                    {
18503
                        JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump()));
18504
                    }
18505
18506
                    break;
18507
                }
18508
18509
                case patch_operations::invalid:
18510
                {
18511
                    // op must be "add", "remove", "replace", "move", "copy", or
18512
                    // "test"
18513
                    JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid"));
18514
                }
18515
            }
18516
        }
18517
18518
        return result;
18519
    }
18520
18521
    /*!
18522
    @brief creates a diff as a JSON patch
18523
18524
    Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can
18525
    be changed into the value @a target by calling @ref patch function.
18526
18527
    @invariant For two JSON values @a source and @a target, the following code
18528
    yields always `true`:
18529
    @code {.cpp}
18530
    source.patch(diff(source, target)) == target;
18531
    @endcode
18532
18533
    @note Currently, only `remove`, `add`, and `replace` operations are
18534
          generated.
18535
18536
    @param[in] source  JSON value to compare from
18537
    @param[in] target  JSON value to compare against
18538
    @param[in] path    helper value to create JSON pointers
18539
18540
    @return a JSON patch to convert the @a source to @a target
18541
18542
    @complexity Linear in the lengths of @a source and @a target.
18543
18544
    @liveexample{The following code shows how a JSON patch is created as a
18545
    diff for two JSON values.,diff}
18546
18547
    @sa @ref patch -- apply a JSON patch
18548
    @sa @ref merge_patch -- apply a JSON Merge Patch
18549
18550
    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
18551
18552
    @since version 2.0.0
18553
    */
18554
    static basic_json diff(const basic_json& source, const basic_json& target,
18555
                           const std::string& path = "")
18556
    {
18557
        // the patch
18558
        basic_json result(value_t::array);
18559
18560
        // if the values are the same, return empty patch
18561
        if (source == target)
18562
        {
18563
            return result;
18564
        }
18565
18566
        if (source.type() != target.type())
18567
        {
18568
            // different types: replace value
18569
            result.push_back(
18570
            {
18571
                {"op", "replace"}, {"path", path}, {"value", target}
18572
            });
18573
        }
18574
        else
18575
        {
18576
            switch (source.type())
18577
            {
18578
                case value_t::array:
18579
                {
18580
                    // first pass: traverse common elements
18581
                    std::size_t i = 0;
18582
                    while (i < source.size() and i < target.size())
18583
                    {
18584
                        // recursive call to compare array values at index i
18585
                        auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i));
18586
                        result.insert(result.end(), temp_diff.begin(), temp_diff.end());
18587
                        ++i;
18588
                    }
18589
18590
                    // i now reached the end of at least one array
18591
                    // in a second pass, traverse the remaining elements
18592
18593
                    // remove my remaining elements
18594
                    const auto end_index = static_cast<difference_type>(result.size());
18595
                    while (i < source.size())
18596
                    {
18597
                        // add operations in reverse order to avoid invalid
18598
                        // indices
18599
                        result.insert(result.begin() + end_index, object(
18600
                        {
18601
                            {"op", "remove"},
18602
                            {"path", path + "/" + std::to_string(i)}
18603
                        }));
18604
                        ++i;
18605
                    }
18606
18607
                    // add other remaining elements
18608
                    while (i < target.size())
18609
                    {
18610
                        result.push_back(
18611
                        {
18612
                            {"op", "add"},
18613
                            {"path", path + "/" + std::to_string(i)},
18614
                            {"value", target[i]}
18615
                        });
18616
                        ++i;
18617
                    }
18618
18619
                    break;
18620
                }
18621
18622
                case value_t::object:
18623
                {
18624
                    // first pass: traverse this object's elements
18625
                    for (auto it = source.cbegin(); it != source.cend(); ++it)
18626
                    {
18627
                        // escape the key name to be used in a JSON patch
18628
                        const auto key = json_pointer::escape(it.key());
18629
18630
                        if (target.find(it.key()) != target.end())
18631
                        {
18632
                            // recursive call to compare object values at key it
18633
                            auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key);
18634
                            result.insert(result.end(), temp_diff.begin(), temp_diff.end());
18635
                        }
18636
                        else
18637
                        {
18638
                            // found a key that is not in o -> remove it
18639
                            result.push_back(object(
18640
                            {
18641
                                {"op", "remove"}, {"path", path + "/" + key}
18642
                            }));
18643
                        }
18644
                    }
18645
18646
                    // second pass: traverse other object's elements
18647
                    for (auto it = target.cbegin(); it != target.cend(); ++it)
18648
                    {
18649
                        if (source.find(it.key()) == source.end())
18650
                        {
18651
                            // found a key that is not in this -> add it
18652
                            const auto key = json_pointer::escape(it.key());
18653
                            result.push_back(
18654
                            {
18655
                                {"op", "add"}, {"path", path + "/" + key},
18656
                                {"value", it.value()}
18657
                            });
18658
                        }
18659
                    }
18660
18661
                    break;
18662
                }
18663
18664
                default:
18665
                {
18666
                    // both primitive type: replace value
18667
                    result.push_back(
18668
                    {
18669
                        {"op", "replace"}, {"path", path}, {"value", target}
18670
                    });
18671
                    break;
18672
                }
18673
            }
18674
        }
18675
18676
        return result;
18677
    }
18678
18679
    /// @}
18680
18681
    ////////////////////////////////
18682
    // JSON Merge Patch functions //
18683
    ////////////////////////////////
18684
18685
    /// @name JSON Merge Patch functions
18686
    /// @{
18687
18688
    /*!
18689
    @brief applies a JSON Merge Patch
18690
18691
    The merge patch format is primarily intended for use with the HTTP PATCH
18692
    method as a means of describing a set of modifications to a target
18693
    resource's content. This function applies a merge patch to the current
18694
    JSON value.
18695
18696
    The function implements the following algorithm from Section 2 of
18697
    [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396):
18698
18699
    ```
18700
    define MergePatch(Target, Patch):
18701
      if Patch is an Object:
18702
        if Target is not an Object:
18703
          Target = {} // Ignore the contents and set it to an empty Object
18704
        for each Name/Value pair in Patch:
18705
          if Value is null:
18706
            if Name exists in Target:
18707
              remove the Name/Value pair from Target
18708
          else:
18709
            Target[Name] = MergePatch(Target[Name], Value)
18710
        return Target
18711
      else:
18712
        return Patch
18713
    ```
18714
18715
    Thereby, `Target` is the current object; that is, the patch is applied to
18716
    the current value.
18717
18718
    @param[in] patch  the patch to apply
18719
18720
    @complexity Linear in the lengths of @a patch.
18721
18722
    @liveexample{The following code shows how a JSON Merge Patch is applied to
18723
    a JSON document.,merge_patch}
18724
18725
    @sa @ref patch -- apply a JSON patch
18726
    @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396)
18727
18728
    @since version 3.0.0
18729
    */
18730
    void merge_patch(const basic_json& patch)
18731
    {
18732
        if (patch.is_object())
18733
        {
18734
            if (not is_object())
18735
            {
18736
                *this = object();
18737
            }
18738
            for (auto it = patch.begin(); it != patch.end(); ++it)
18739
            {
18740
                if (it.value().is_null())
18741
                {
18742
                    erase(it.key());
18743
                }
18744
                else
18745
                {
18746
                    operator[](it.key()).merge_patch(it.value());
18747
                }
18748
            }
18749
        }
18750
        else
18751
        {
18752
            *this = patch;
18753
        }
18754
    }
18755
18756
    /// @}
18757
};
18758
} // namespace nlohmann
18759
18760
///////////////////////
18761
// nonmember support //
18762
///////////////////////
18763
18764
// specialization of std::swap, and std::hash
18765
namespace std
18766
{
18767
18768
/// hash value for JSON objects
18769
template<>
18770
struct hash<nlohmann::json>
18771
{
18772
    /*!
18773
    @brief return a hash value for a JSON object
18774
18775
    @since version 1.0.0
18776
    */
18777
    std::size_t operator()(const nlohmann::json& j) const
18778
0
    {
18779
0
        // a naive hashing via the string representation
18780
0
        const auto& h = hash<nlohmann::json::string_t>();
18781
0
        return h(j.dump());
18782
0
    }
18783
};
18784
18785
/// specialization for std::less<value_t>
18786
/// @note: do not remove the space after '<',
18787
///        see https://github.com/nlohmann/json/pull/679
18788
template<>
18789
struct less< ::nlohmann::detail::value_t>
18790
{
18791
    /*!
18792
    @brief compare two value_t enum values
18793
    @since version 3.0.0
18794
    */
18795
    bool operator()(nlohmann::detail::value_t lhs,
18796
                    nlohmann::detail::value_t rhs) const noexcept
18797
0
    {
18798
0
        return nlohmann::detail::operator<(lhs, rhs);
18799
0
    }
18800
};
18801
18802
/*!
18803
@brief exchanges the values of two JSON objects
18804
18805
@since version 1.0.0
18806
*/
18807
template<>
18808
inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept(
18809
    is_nothrow_move_constructible<nlohmann::json>::value and
18810
    is_nothrow_move_assignable<nlohmann::json>::value
18811
)
18812
0
{
18813
0
    j1.swap(j2);
18814
0
}
18815
18816
} // namespace std
18817
18818
/*!
18819
@brief user-defined string literal for JSON values
18820
18821
This operator implements a user-defined string literal for JSON objects. It
18822
can be used by adding `"_json"` to a string literal and returns a JSON object
18823
if no parse error occurred.
18824
18825
@param[in] s  a string representation of a JSON object
18826
@param[in] n  the length of string @a s
18827
@return a JSON object
18828
18829
@since version 1.0.0
18830
*/
18831
inline nlohmann::json operator "" _json(const char* s, std::size_t n)
18832
0
{
18833
0
    return nlohmann::json::parse(s, s + n);
18834
0
}
18835
18836
/*!
18837
@brief user-defined string literal for JSON pointer
18838
18839
This operator implements a user-defined string literal for JSON Pointers. It
18840
can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer
18841
object if no parse error occurred.
18842
18843
@param[in] s  a string representation of a JSON Pointer
18844
@param[in] n  the length of string @a s
18845
@return a JSON pointer object
18846
18847
@since version 2.0.0
18848
*/
18849
inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
18850
0
{
18851
0
    return nlohmann::json::json_pointer(std::string(s, n));
18852
0
}
18853
18854
// #include <nlohmann/detail/macro_unscope.hpp>
18855
18856
18857
// restore GCC/clang diagnostic settings
18858
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
18859
    #pragma GCC diagnostic pop
18860
#endif
18861
#if defined(__clang__)
18862
    #pragma GCC diagnostic pop
18863
#endif
18864
18865
// clean up
18866
#undef JSON_INTERNAL_CATCH
18867
#undef JSON_CATCH
18868
#undef JSON_THROW
18869
#undef JSON_TRY
18870
#undef JSON_LIKELY
18871
#undef JSON_UNLIKELY
18872
#undef JSON_DEPRECATED
18873
#undef JSON_HAS_CPP_14
18874
#undef JSON_HAS_CPP_17
18875
#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION
18876
#undef NLOHMANN_BASIC_JSON_TPL
18877
18878
18879
#endif
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/sunrise-sunset/sunriseset.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "sunriseset.h"
2
3
double SunRiseSet::FNday(int y, int m, int d, float h)
4
183
{
5
183
    long int luku = - 7 * (y + (m + 9)/12)/4 + 275*m/9 + d;
6
183
7
183
    // Typecasting needed for TClite on PC DOS at least, to avoid product overflow
8
183
    luku+= (long int)y*367;
9
183
10
183
    return (double)luku - 730531.5 + h/24.0;
11
183
}
12
double SunRiseSet::FNrange(double x)
13
549
{
14
549
    double b = x / tpi;
15
549
    double a = tpi * (b - (long)(b));
16
549
    if (a < 0) a = tpi + a;
17
549
    return a;
18
549
}
19
20
double SunRiseSet::f0(double lat, double declin)
21
183
{
22
183
    double fo,dfo;
23
183
    // Correction: different sign at S HS
24
183
    dfo = rads*(0.5*SunDia + AirRefr); if (lat < 0.0) dfo = -dfo;
25
183
    fo = tan(declin + dfo) * tan(lat*rads);
26
183
27
183
    if (fo > 0.99999) fo=1.0; // to avoid overflow //
28
183
    fo = asin(fo) + pi/2.0;
29
183
    return fo;
30
183
}
31
32
double SunRiseSet::f1(double lat, double declin)
33
4
{
34
4
    double fi,df1;
35
4
    // Correction: different sign at S HS
36
4
    df1 = rads * 6.0; if (lat < 0.0) df1 = -df1;
37
4
    fi = tan(declin + df1) * tan(lat*rads);
38
4
39
4
    if (fi > 0.99999) fi=1.0; // to avoid overflow //
40
4
    fi = asin(fi) + pi/2.0;
41
4
    return fi;
42
4
}
43
44
double SunRiseSet::FNsun(double d)
45
183
{
46
183
    // mean longitude of the Sun
47
183
    L = FNrange(280.461 * rads + .9856474 * rads * d);
48
183
49
183
    // mean anomaly of the Sun
50
183
    g = FNrange(357.528 * rads + .9856003 * rads * d);
51
183
52
183
    // Ecliptic longitude of the Sun
53
183
    return FNrange(L + 1.915 * rads * sin(g) + .02 * rads * sin(2 * g));
54
183
}
55
56
Clock SunRiseSet::gethrmn(double dhr)
57
219
{
58
219
59
219
    int hr,mn;
60
219
61
219
    hr=(int) dhr;
62
219
    mn = (dhr - (double) hr)*60;
63
219
64
219
    Clock ret(hr,mn);
65
219
66
219
    return ret;
67
219
}
68
69
SunRiseSet::SunRiseSet()
70
796
{
71
796
72
796
}
73
74
std::string SunRiseSet::getAllData()
75
4
{
76
4
    double y,m,day,h,latit,longit;
77
4
78
4
    time_t sekunnit;
79
4
    struct tm *p;
80
4
81
4
    // get the date and time from the user
82
4
    // read system date and extract the year
83
4
84
4
    /** First get current time **/
85
4
    time(&sekunnit);
86
4
87
4
    /** Next get localtime **/
88
4
89
4
    p=localtime(&sekunnit);
90
4
    // this is Y2K compliant algorithm
91
4
    y = 1900 + p->tm_year;
92
4
93
4
    m = p->tm_mon + 1;
94
4
    day = p->tm_mday;
95
4
    h = 12;
96
4
97
4
    std::cout << "Input latitude, longitude and timezone\n";
98
4
    latit = LATITUDE;
99
4
    longit = LONGITUDE;
100
4
    // Timezone hours
101
4
    double tzone= TIMEZONE;
102
4
    double d = FNday(y, m, day, h);
103
4
104
4
    // Use FNsun to find the ecliptic longitude of the
105
4
    // Sun
106
4
    double lambda = FNsun(d);
107
4
108
4
    // Obliquity of the ecliptic
109
4
    double obliq = 23.439 * rads - .0000004 * rads * d;
110
4
111
4
    // Find the RA and DEC of the Sun
112
4
    double alpha = atan2(cos(obliq) * sin(lambda), cos(lambda));
113
4
    double delta = asin(sin(obliq) * sin(lambda));
114
4
115
4
    // Find the Equation of Time in minutes
116
4
    // Correction suggested by David Smith
117
4
    double LL = L - alpha;
118
4
    if (L < pi) LL += tpi;
119
4
    double equation = 1440.0 * (1.0 - LL / tpi);
120
4
    double ha = f0(latit,delta);
121
4
    double hb = f1(latit,delta);
122
4
    double twx = hb - ha;   // length of twilight in radians
123
4
    twx = 12.0*twx/pi;      // length of twilight in degrees
124
4
125
4
    // Conversion of angle to hours and minutes //
126
4
    daylen = degs * ha / 7.5;
127
4
    if (daylen<0.0001) {daylen = 0.0;}
128
4
    // arctic winter   //
129
4
130
4
    double riset = 12.0 - 12.0 * ha/pi + tzone - longit/15.0 + equation/60.0;
131
4
    double settm = 12.0 + 12.0 * ha/pi + tzone - longit/15.0 + equation/60.0;
132
4
    //double noont = riset + 12.0 * ha/pi;
133
4
    //double altmax = 90.0 + delta * degs - latit;
134
4
    // Correction suggested by David Smith
135
4
    // to express as degrees from the N horizon
136
4
137
4
    //if (delta * degs > latit ) altmax = 90.0 + latit - delta * degs;
138
4
139
4
    double twam = riset - twx;    // morning twilight begin
140
4
    double twpm = settm + twx;      // evening twilight end
141
4
142
4
    if (riset > 24.0) riset-= 24.0;
143
4
    if (settm > 24.0) settm-= 24.0;
144
4
145
4
    std::stringstream ss;
146
4
    ss << "\n Sunrise and set\n";
147
4
    ss << "===============\n";
148
4
    ss << "  year  : " << y << '\n';
149
4
    ss << "  month : " << m << '\n';
150
4
    ss << "  day   : " << day << "\n\n";
151
4
    ss << "Days until Y2K :  " << d << '\n';
152
4
    ss << "Latitude :  " << latit << ", longitude:  " << longit << '\n';
153
4
    ss << "Timezone :  " << tzone << "\n\n";
154
4
    ss << "Declination : " << delta * degs << '\n';
155
4
    ss << "Daylength   : "<< gethrmn(daylen).m_h<<":"<<gethrmn(daylen).m_min<< " hours \n";
156
4
    ss << "Begin civil twilight: "<<
157
4
                 gethrmn(twam).m_h<<":"<<gethrmn(twam).m_min; std::cout << '\n';
158
4
159
4
    ss << "Sunrise     : "<< gethrmn(riset).m_h<<":"<<gethrmn(riset).m_min; std::cout << '\n';
160
4
    ss << "Sun altitude at noontime ";
161
4
162
4
163
4
    ss << "Sunset      : "<<
164
4
                 gethrmn(settm).m_h<<":"<<gethrmn(settm).m_min; std::cout << '\n';
165
4
    ss << "Civil twilight: "<<
166
4
                 gethrmn(twpm).m_h<<":"<<gethrmn(twpm).m_min; std::cout << '\n';
167
4
    return ss.str();
168
4
}
169
170
void SunRiseSet::setPosition(double LATITUDE, double LONGITUDE, int TIMEZONE)
171
0
{
172
0
    this->LATITUDE = LATITUDE;
173
0
    this->LONGITUDE = LONGITUDE;
174
0
    this->TIMEZONE = TIMEZONE;
175
0
}
176
177
Clock SunRiseSet::getSunRise()
178
100
{
179
100
    double y,m,day,h,latit,longit;
180
100
    time_t sekunnit;
181
100
    struct tm *p;
182
100
    // get the date and time from the user
183
100
    // read system date and extract the year
184
100
185
100
    /** First get current time **/
186
100
    time(&sekunnit);
187
100
188
100
    /** Next get localtime **/
189
100
    p=localtime(&sekunnit);
190
100
    // this is Y2K compliant algorithm
191
100
    y = 1900 + p->tm_year;
192
100
    m = p->tm_mon + 1;
193
100
    day = p->tm_mday;
194
100
    h = 12;
195
100
    latit = LATITUDE;
196
100
    longit = LONGITUDE;
197
100
    // Timezone hours
198
100
    double tzone = TIMEZONE;
199
100
    double d = FNday(y, m, day, h);
200
100
    // Use FNsun to find the ecliptic longitude of the
201
100
    // Sun
202
100
    double lambda = FNsun(d);
203
100
    // Obliquity of the ecliptic
204
100
    double obliq = 23.439 * rads - .0000004 * rads * d;
205
100
    // Find the RA and DEC of the Sun
206
100
    double alpha = atan2(cos(obliq) * sin(lambda), cos(lambda));
207
100
    double delta = asin(sin(obliq) * sin(lambda));
208
100
    double LL = L - alpha;
209
100
    if (L < pi) LL += tpi;
210
100
    double equation = 1440.0 * (1.0 - LL / tpi);
211
100
    double ha = f0(latit,delta);
212
100
    // Conversion of angle to hours and minutes //
213
100
    daylen = degs * ha / 7.5;
214
100
    if (daylen<0.0001) {daylen = 0.0;}
215
100
    // arctic winter   //
216
100
    double riset = 12.0 - 12.0 * ha/pi + tzone - longit/15.0 + equation/60.0;
217
100
218
100
    if (riset > 24.0) riset-= 24.0;
219
100
    return  gethrmn(riset);
220
100
}
221
222
Clock SunRiseSet::getDayLength()
223
28
{
224
28
    double y,m,day,h,latit;
225
28
    time_t sekunnit;
226
28
    struct tm *p;
227
28
228
28
    // get the date and time from the user
229
28
    // read system date and extract the year
230
28
231
28
    /** First get current time **/
232
28
    time(&sekunnit);
233
28
234
28
    /** Next get localtime **/
235
28
    p=localtime(&sekunnit);
236
28
    // this is Y2K compliant algorithm
237
28
    y = 1900 + p->tm_year;
238
28
    m = p->tm_mon + 1;
239
28
    day = p->tm_mday;
240
28
    h = 12;
241
28
    latit = LATITUDE;
242
28
    double d = FNday(y, m, day, h);
243
28
244
28
    // Use FNsun to find the ecliptic longitude of the
245
28
    // Sun
246
28
    double lambda = FNsun(d);
247
28
    // Obliquity of the ecliptic
248
28
    double obliq = 23.439 * rads - .0000004 * rads * d;
249
28
    double delta = asin(sin(obliq) * sin(lambda));
250
28
    // Find the Equation of Time in minutes
251
28
    // Correction suggested by David Smith
252
28
    double ha = f0(latit,delta);
253
28
    // Conversion of angle to hours and minutes //
254
28
    daylen = degs * ha / 7.5;
255
28
    if (daylen<0.0001) {daylen = 0.0;}
256
28
    // arctic winter   //
257
28
258
28
    return  gethrmn(daylen);
259
28
}
260
261
Clock SunRiseSet::getSunSet()
262
51
{
263
51
    double y,m,day,h,latit,longit;
264
51
265
51
    time_t sekunnit;
266
51
    struct tm *p;
267
51
268
51
    // get the date and time from the user
269
51
    // read system date and extract the year
270
51
271
51
    /** First get current time **/
272
51
    time(&sekunnit);
273
51
274
51
    /** Next get localtime **/
275
51
276
51
    p=localtime(&sekunnit);
277
51
    // this is Y2K compliant algorithm
278
51
    y = 1900 + p->tm_year;
279
51
280
51
    m = p->tm_mon + 1;
281
51
    day = p->tm_mday;
282
51
    h = 12;
283
51
284
51
    latit = LATITUDE;
285
51
    longit = LONGITUDE;
286
51
    // Timezone hours
287
51
    double tzone = TIMEZONE;
288
51
289
51
    double d = FNday(y, m, day, h);
290
51
291
51
    // Use FNsun to find the ecliptic longitude of the
292
51
    // Sun
293
51
294
51
    double lambda = FNsun(d);
295
51
296
51
    // Obliquity of the ecliptic
297
51
298
51
    double obliq = 23.439 * rads - .0000004 * rads * d;
299
51
300
51
    // Find the RA and DEC of the Sun
301
51
302
51
    double alpha = atan2(cos(obliq) * sin(lambda), cos(lambda));
303
51
    double delta = asin(sin(obliq) * sin(lambda));
304
51
305
51
306
51
    // Find the Equation of Time in minutes
307
51
    // Correction suggested by David Smith
308
51
309
51
    double LL = L - alpha;
310
51
    if (L < pi) LL += tpi;
311
51
    double equation = 1440.0 * (1.0 - LL / tpi);
312
51
313
51
314
51
    double ha = f0(latit,delta);
315
51
316
51
    // Conversion of angle to hours and minutes //
317
51
    daylen = degs * ha / 7.5;
318
51
    if (daylen<0.0001) {daylen = 0.0;}
319
51
    // arctic winter   //
320
51
321
51
    //double riset = 12.0 - 12.0 * ha/pi + tzone - longit/15.0 + equation/60.0;
322
51
    double settm = 12.0 + 12.0 * ha/pi + tzone - longit/15.0 + equation/60.0;
323
51
324
51
    //if (riset > 24.0) riset-= 24.0;
325
51
    if (settm > 24.0) settm-= 24.0;
326
51
    return  gethrmn(settm);
327
51
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/useful/test/useful_bt.cpp
Line
Count
Source
1
#include <gtest/gtest.h>
2
#include <gmock/gmock.h>
3
#include <sys/types.h>
4
#include <sys/stat.h>
5
#include <stdio.h>
6
#include <string.h>
7
#include <fcntl.h>
8
#include <unistd.h>
9
#include "../useful.h"
10
///////////////////////////////////////////////////// TEST ///////////////////////////////////////////////////////\
11
12
TEST(ClockClass, AddTwoHours)
13
4
{
14
4
    Clock f(13,57);
15
4
    Clock g(23,59);
16
4
    Clock r = f+g;
17
4
    EXPECT_EQ(r.getString(), "13:56");
18
4
}
19
20
TEST(ClockClass, lessThen_Hours)
21
4
{
22
4
    Clock f(13,57);
23
4
    Clock g(23,59);
24
4
    EXPECT_EQ(f<g, true);
25
4
}
26
27
TEST(ClockClass, plus_operator)
28
4
{
29
4
    Clock f(13,57);
30
4
    f+=Clock("04:04");
31
4
    EXPECT_EQ(f.getString(),"18:01");
32
4
}
33
34
TEST(ClockClass, _operator)
35
4
{
36
4
    EXPECT_FALSE(Clock("04:04") == Clock("04:05"));
37
4
    EXPECT_FALSE(Clock("05:05") == Clock("04:05"));
38
4
    EXPECT_TRUE(Clock("05:05") == Clock("05:05"));
39
4
    EXPECT_FALSE(Clock("05:05") != Clock("05:05"));
40
4
    EXPECT_TRUE(Clock("04:05") != Clock("05:05"));
41
4
    EXPECT_TRUE(Clock("04:05") != Clock("04:04"));
42
4
    EXPECT_TRUE(Clock("04:05") > Clock("04:04"));
43
4
    EXPECT_FALSE(Clock("03:05") > Clock("04:04"));
44
4
    EXPECT_TRUE(Clock("04:05") >= Clock("04:04"));
45
4
    EXPECT_FALSE(Clock("04:05") <= Clock("04:04"));
46
4
    EXPECT_FALSE(Clock("05:05") <= Clock("04:05"));
47
4
    EXPECT_TRUE(Clock("03:05") <= Clock("04:05"));
48
4
    EXPECT_TRUE(Clock("04:05") <= Clock("04:06"));
49
4
    EXPECT_FALSE(Clock("05:05") < Clock("04:06"));
50
4
    EXPECT_TRUE(Clock("04:05") < Clock("04:06"));
51
4
    EXPECT_TRUE(Clock("08:05") > Clock("04:06"));
52
4
53
4
    std::stringstream s;
54
4
    Clock f("00:00");
55
4
    s << f;
56
4
    EXPECT_STREQ("00:00", s.str().c_str());
57
4
58
4
    Clock g("20:00");
59
4
    f = g.getTime();
60
4
    g += Clock("23:43");
61
4
    EXPECT_STREQ("19:43", g.getString().c_str());
62
4
}
63
64
TEST(ClockClass, periodOfTime)
65
4
{
66
4
    Clock f(13,57);
67
4
    Clock g(22,22);
68
4
    Clock r = Clock::periodOfTime(f,g);
69
4
    EXPECT_EQ(r.getString(),"08:25");
70
4
    r = Clock::periodOfTime(g,f);
71
4
    EXPECT_EQ(r.getString(),"15:35");
72
4
}
73
74
TEST(ClockClass, from_to_second)
75
4
{
76
4
    Clock f;
77
4
    f.set(13,57);
78
4
    unsigned int sec = f.toSeconds();
79
4
    Clock g = Clock::fromSeconds(sec);
80
4
    EXPECT_EQ(f.getString(),g.getString());
81
4
}
82
83
TEST(ClockClass, stopwatch)
84
4
{
85
4
    Clock f;
86
4
    f.stopwatchStart();
87
4
    sleep(1);
88
4
    EXPECT_EQ(1,f.stopwatchStopAndGetResult());
89
4
}
90
91
TEST(ClockClass, wrongSet)
92
4
{
93
4
    Clock f;
94
4
    EXPECT_ANY_THROW(f.set(99,99));
95
4
}
96
97
TEST(ClockClass, to_string_with_precision_TC)
98
4
{
99
4
    double d = 1.0/3.0;
100
4
    EXPECT_STREQ("0.33", to_string_with_precision(d,2).c_str() );
101
4
}
102
103
TEST(JSON, getJSON)
104
4
{
105
4
    nlohmann::json test_JSON = useful_F_libs::getJson("http://cyniu88.no-ip.pl/test/json/on_lightning.json");
106
4
    auto testKey = test_JSON["success"].get<bool>();
107
4
108
4
    std::cout << " JSON JEST" << std::endl << test_JSON.dump(4) << std::endl;
109
4
110
4
    EXPECT_TRUE(testKey);
111
4
}
112
113
//TEST(mkfifo_test, mkfifoFile)
114
//{
115
//    std::string path = "/mnt/ramdisk/FifoFile";
116
//    std::string msg = "p";
117
//    std::string returnString = "NULL";
118
//    int temp = mkfifo(path.c_str(),0666);
119
120
//    if ( temp == -1)
121
//        std::cout << "plik istnieje "<<strerror(errno)<< std::endl;
122
//    else if (temp == 0)
123
//        std::cout << "plik stworzony"<< std::endl;
124
//    else
125
//        FAIL();
126
127
//    useful_F_libs::write_to_mkfifo(path,msg);
128
//}
129
130
//TEST(mkfifo_test, mkfifoFile2)
131
//{
132
//    std::string msg = "p";
133
//    std::string path = "/mnt/ramdisk/FifoFile";
134
//    std::string returnString = useful_F_libs::read_from_mkfifo(path);
135
//    //unlink(path.c_str());
136
137
//    EXPECT_STREQ(returnString.c_str(), msg.c_str()) << "odczytano smieci";
138
//    //TODO not
139
140
//}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/useful/useful.h
Line
Count
Source
1
#ifndef Iusefull_H
2
#define Iusefull_H
3
4
#include <iostream>
5
#include <string>
6
#include <vector>
7
#include <ostream>
8
#include <chrono>
9
#include <sstream>
10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <iomanip>
13
#ifndef ANDROID
14
#include "json.hpp"
15
#endif
16
17
std::vector<std::string> split_string(const std::string& s, char separator );
18
19
class useful_F_libs {
20
public:
21
    static  void write_to_mkfifo(const std::string& path, const std::string &msg);
22
    static  std::string read_from_mkfifo(const std::string &path);
23
    static size_t  WriteCallback(void *contents, size_t size, size_t nmemb, void *userp);
24
    static std::string find_tag (const std::string &temp);
25
    //////////////////// HTTP req //////////////////////////
26
    static std::string httpPost(const std::string &url, int timeoutSeconds);
27
    static std::string httpPost(const std::string &url);
28
    static void downloadFile(const std::string &url, const std::string &path, int timeoutSeconds);
29
    static std::string replaceAll(std::string str, const std::string& from, const std::string& to);
30
    static std::string removeHtmlTag(std::string &data);
31
    /////////////////////  JSON ////////////////////////////
32
33
#ifndef ANDROID
34
    static nlohmann::json getJson(const std::string &url);
35
#endif
36
};
37
namespace std
38
{
39
40
#ifdef ANDROID
41
template <typename T>
42
int stoi(T s){
43
    return atoi(s.c_str());
44
}
45
#endif
46
47
template <typename T>
48
std::string to_string(T value)
49
8
{
50
8
    std::ostringstream os;
51
8
    os << value;
52
8
    return os.str();
53
8
}
54
} // namespace std
55
56
template <typename T>
57
std::string to_string_with_precision(const T a_value, const int n = 4)
58
312
{
59
312
    std::ostringstream out;
60
312
    out << std::setprecision(n) << a_value;
61
312
    return out.str();
62
312
}
_Z24to_string_with_precisionIdENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEET_i
Line
Count
Source
58
236
{
59
236
    std::ostringstream out;
60
236
    out << std::setprecision(n) << a_value;
61
236
    return out.str();
62
236
}
_Z24to_string_with_precisionIiENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEET_i
Line
Count
Source
58
76
{
59
76
    std::ostringstream out;
60
76
    out << std::setprecision(n) << a_value;
61
76
    return out.str();
62
76
}
63
64
struct Clock{
65
private:
66
    std::time_t m_time;
67
#ifdef BT_TEST
68
    static unsigned int m_BT_H;
69
    static unsigned int m_BT_M;
70
#endif
71
public:
72
    unsigned int m_h = 0;
73
    unsigned int m_min = 0;
74
4.02k
    Clock () {}
75
148
    Clock(std::string t){
76
148
        std::vector<std::string> vt = split_string(t,':');
77
148
        int h = std::stoi(vt.at(0));
78
148
        int m = std::stoi(vt.at(1));
79
148
        set(static_cast <unsigned int>(h),static_cast <unsigned int>(m));
80
148
    }
81
82
2.86k
    Clock(unsigned int h, unsigned int m) {
83
2.86k
        set(h,m);
84
2.86k
    }
85
    /////////////////////////////////////////////////////////////////////////////////////
86
3.01k
    void set(unsigned int h, unsigned int m){
87
3.01k
        if (h<24 && m <60){
88
3.01k
            this->m_h = h;
89
3.01k
            this->m_min = m;
90
3.01k
        }
91
4
        else {
92
4
            throw 0;
93
4
        }
94
3.01k
    }
95
96
    /////////////////////////////////////////////////////////////////////////////////////
97
332
    const std::string getString(){
98
332
        std::stringstream ret;
99
332
        if (m_h < 10) {
100
267
            ret << "0";
101
267
        }
102
332
        ret << m_h;
103
332
        ret << ":";
104
332
        if (m_min < 10) {
105
229
            ret << "0";
106
229
        }
107
332
        ret << m_min;
108
332
        return ret.str();
109
332
    }
110
    /////////////////////////////////////////////////////////////////////////////////////
111
52
    bool operator == (const Clock & c){
112
52
        if ((this->m_h == c.m_h) && (this->m_min == c.m_min)){
113
44
            return true;
114
44
        }
115
8
        else{
116
8
            return false;
117
8
        }
118
52
    }
119
    /////////////////////////////////////////////////////////////////////////////////////
120
52
    bool operator != (const Clock & c){
121
52
        if ((this->m_h != c.m_h) || (this->m_min != c.m_min)){
122
32
            return true;
123
32
        }
124
20
        else{
125
20
            return false;
126
20
        }
127
52
    }
128
    /////////////////////////////////////////////////////////////////////////////////////
129
4
    friend std::ostream & operator<< (std::ostream &w ,  Clock &c) {
130
4
        return w << c.getString();
131
4
    }
132
    /////////////////////////////////////////////////////////////////////////////////////
133
72
    bool operator < (const Clock& c){
134
72
        if (this->m_h < c.m_h){
135
53
            return true;
136
53
        }
137
19
        else{
138
19
            if (this->m_h == c.m_h && this->m_min < c.m_min){
139
4
                return true;
140
4
            }
141
15
        }
142
15
        return false;
143
15
    }
144
    /////////////////////////////////////////////////////////////////////////////////////
145
23
    bool operator > (const Clock& c){
146
23
        if (this->m_h > c.m_h){
147
11
            return true;
148
11
        }
149
12
        else{
150
12
            if (this->m_h == c.m_h && this->m_min > c.m_min){
151
4
                return true;
152
4
            }
153
8
        }
154
8
        return false;
155
8
    }
156
    /////////////////////////////////////////////////////////////////////////////////////
157
20
    bool operator >= (const Clock& c){
158
20
        if (this->m_h > c.m_h){
159
8
            return true;
160
8
        }
161
12
        else if (this->m_h == c.m_h){
162
4
163
4
            if (this->m_min >= c.m_min){
164
4
                return true;
165
4
            }
166
8
        }
167
8
        return false;
168
8
    }
169
    /////////////////////////////////////////////////////////////////////////////////////
170
28
    bool operator <= (const Clock& c){
171
28
        if (this->m_h < c.m_h){
172
8
            return true;
173
8
        }
174
20
        else if (this->m_h == c.m_h){
175
8
176
8
            if (this->m_min <= c.m_min){
177
4
                return true;
178
4
            }
179
16
        }
180
16
        return false;
181
16
    }
182
    /////////////////////////////////////////////////////////////////////////////////////
183
788
    Clock  operator + (const Clock& c){
184
788
        unsigned int minutes, hours;
185
788
        minutes = m_min+ c.m_min;
186
788
        hours = m_h + c.m_h;
187
788
        if (minutes >59){
188
751
            minutes =  minutes % 60;
189
751
            hours+=1;
190
751
        }
191
788
        if (hours >= 24){
192
751
            hours-=24;
193
751
        }
194
788
        return  Clock(hours, minutes);
195
788
196
788
    }
197
    /////////////////////////////////////////////////////////////////////////////////////
198
20
    Clock&  operator += (const Clock& c){
199
20
        unsigned int minutes, hours;
200
20
        minutes = m_min+ c.m_min;
201
20
        hours = m_h + c.m_h;
202
20
        if (minutes >59){
203
16
            minutes =  minutes % 60;
204
16
            hours+=1;
205
16
        }
206
20
        if (hours >= 24){
207
16
            hours-=24;
208
16
        }
209
20
        this->m_h = hours;
210
20
        this->m_min = minutes;
211
20
        return *this;
212
20
213
20
    }
214
    /////////////////////////////////////////////////////////////////////////////////////
215
216
20
    unsigned int toSeconds(){
217
20
        return toSeconds(Clock(this->m_h, this->m_min) );
218
20
    }
219
    /////////////////////////////////////////////////////////////////////////////////////
220
221
24
    static unsigned int toSeconds(Clock t){
222
24
        return ((t.m_h*60) + t.m_min)*60;
223
24
    }
224
    /////////////////////////////////////////////////////////////////////////////////////
225
226
12
    static Clock fromSeconds(unsigned int sec){
227
12
        unsigned int h = sec/3600;
228
12
        unsigned int min = sec%3600;
229
12
        min = min/60;
230
12
        return Clock(h,min);
231
12
    }
232
    /////////////////////////////////////////////////////////////////////////////////////
233
234
    static Clock periodOfTime(Clock start, Clock end)
235
8
    {
236
8
        if (end >= start){
237
4
            return Clock::fromSeconds(end.toSeconds() - start.toSeconds()  );
238
4
        }
239
4
        else{
240
4
            return Clock::fromSeconds(end.toSeconds() + ( Clock::toSeconds(Clock(23,59))+ 60 - start.toSeconds() ) );
241
4
        }
242
8
        //return diff;
243
8
    }
244
    ////////////////////////////////////////////////////////////////////////////////////
245
    static unsigned int getUnixTime()
246
16
    {
247
16
        return static_cast<unsigned int> (std::time(nullptr));
248
16
    }
249
    /////////////////////////////////////////////////////////////////////////////////////
250
#ifdef BT_TEST
251
    static void setTime_forBT_usage(int h, int m)
252
24
    {
253
24
        m_BT_H = h;
254
24
        m_BT_M = m;
255
24
    }
256
#endif
257
    /////////////////////////////////////////////////////////////////////////////////////
258
    static Clock getTime()
259
996
    {
260
996
#ifdef BT_TEST
261
996
        return Clock(m_BT_H,m_BT_M);
262
#else
263
        time_t now = time(0);
264
        tm *ltm = localtime(&now);
265
        return Clock( static_cast <unsigned int>(ltm->tm_hour),static_cast <unsigned int>(ltm->tm_min) );
266
#endif
267
    }
268
    /////////////////////////////////////////////////////////////////////////////////////
269
    void stopwatchStart()
270
4
    {
271
4
        m_time = std::time(nullptr);
272
4
    }
273
    /////////////////////////////////////////////////////////////////////////////////////
274
    unsigned int  stopwatchStopAndGetResult()
275
4
    {
276
4
        return static_cast<unsigned int>(std::time(nullptr) - m_time);
277
4
    }
278
};
279
280
enum class STATE {
281
    OFF,
282
    ON,
283
    UNKNOWN,
284
    PLAY,
285
    PAUSE,
286
    STOP,
287
    ACTIVE,
288
    DEACTIVE,
289
    WORKING,
290
    DEFINE,
291
    UNDEFINE,
292
    LOCK,
293
    UNLOCK,
294
    EMPTY,
295
    FULL,
296
    SEND_OK,
297
    SEND_NOK,
298
    TEMPORARY
299
    //WARNING remember add new state to stateToString() usefull.cpp
300
};
301
302
303
std::string stateToString(STATE s);
304
STATE stringToState(const std::string& s);
305
306
#endif
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/libs/useful/usefull.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "useful.h"
2
#include <sys/fcntl.h>
3
#include <unistd.h>
4
#include <sys/types.h>
5
#include <sys/stat.h>
6
#include <fcntl.h>
7
#include <fstream>
8
9
#ifndef IDOM
10
#include <curl/curl.h>
11
#endif
12
148
std::vector<std::string> split_string(const std::string& s, char separator ){
13
148
    std::vector<std::string> output;
14
148
    std::string::size_type prev_pos = 0, pos = 0;
15
148
16
296
    while((pos = s.find(separator, pos)) != std::string::npos)
17
148
    {
18
148
        std::string substring( s.substr(prev_pos, pos-prev_pos) );
19
148
        output.push_back(substring);
20
148
        prev_pos = ++pos;
21
148
    }
22
148
    try {
23
148
        output.push_back(s.substr(prev_pos, pos-prev_pos)); // Last word
24
148
    }
25
148
    catch (...){
26
0
27
0
    }
28
148
    return output;
29
148
}
30
31
2.74k
std::string stateToString(STATE s){
32
2.74k
    switch (s) {
33
2.74k
    case STATE::OFF:        return "OFF";
34
2.74k
    case STATE::ON:         return "ON";
35
2.74k
    case STATE::PLAY:       return "PLAY";
36
2.74k
    case STATE::PAUSE:      return "PAUSE";
37
2.74k
    case STATE::STOP:       return "STOP";
38
2.74k
    case STATE::ACTIVE:     return "ACTIVE";
39
2.74k
    case STATE::DEACTIVE:   return "DEACTIVE";
40
2.74k
    case STATE::WORKING:    return "WORKING";
41
2.74k
    case STATE::DEFINE:     return "DEFINE";
42
2.74k
    case STATE::UNDEFINE:   return "UNDEFINE";
43
2.74k
    case STATE::LOCK:       return "LOCK";
44
2.74k
    case STATE::UNLOCK:     return "UNLOCK";
45
2.74k
    case STATE::EMPTY:      return "EMPTY";
46
2.74k
    case STATE::FULL:       return "FULL";
47
2.74k
    case STATE::SEND_OK:    return "SEND_OK";
48
2.74k
    case STATE::SEND_NOK:   return "SEND_NOK";
49
2.74k
    default:
50
184
        return "UNKNOWN";
51
0
    }
52
0
}
53
54
7.94k
STATE stringToState(const std::string& s){
55
7.94k
    if(s == "OFF")
56
1.57k
        return STATE::OFF;
57
6.36k
    else if (s == "ON")
58
1.57k
        return STATE::ON;
59
4.79k
    else if (s == "PLAY")
60
0
        return STATE::PLAY;
61
4.79k
    else if (s == "PAUSE")
62
0
        return STATE::PAUSE;
63
4.79k
    else if (s == "STOP")
64
0
        return STATE::STOP;
65
4.79k
    else if (s == "ACTIVE")
66
0
        return STATE::ACTIVE;
67
4.79k
    else if (s == "DEACTIVE")
68
0
        return STATE::DEACTIVE;
69
4.79k
    else if (s == "WORKING")
70
0
        return STATE::WORKING;
71
4.79k
    else if (s == "DEFINE")
72
0
        return STATE::DEFINE;
73
4.79k
    else if (s == "UNDEFINE")
74
0
        return STATE::UNDEFINE;
75
4.79k
    else if (s == "LOCK")
76
0
        return STATE::LOCK;
77
4.79k
    else if (s == "UNLOCK")
78
0
        return STATE::UNLOCK;
79
4.79k
    else if (s == "EMPTY")
80
0
        return STATE::EMPTY;
81
4.79k
    else if (s == "FULL")
82
0
        return STATE::FULL;
83
4.79k
    else if (s == "SEND_OK")
84
0
        return STATE::SEND_OK;
85
4.79k
    else if (s == "SEND_NOK")
86
0
        return STATE::SEND_NOK;
87
4.79k
    else
88
4.79k
        return STATE::UNKNOWN;
89
0
}
90
91
#ifndef IDOM
92
void useful_F_libs::write_to_mkfifo(const std::string &path, const std::string& msg)
93
24
{
94
24
    errno = 0;
95
24
    int fd = open(path.c_str(), O_RDWR| O_NONBLOCK );
96
24
    std::cout << "write open file: " << fd << " path " << path.c_str() << " msg: " << msg <<std::endl;
97
24
    std::cout << "write_to_mkfifo( error - " << strerror(  errno ) <<   std::endl;
98
24
    write(fd, msg.c_str(), msg.size());
99
24
    close(fd);
100
24
}
101
102
std::string useful_F_libs::read_from_mkfifo(const std::string& path)
103
44
{
104
44
    /* char buf[10];
105
44
    //open, read, and display the message from the FIFO
106
44
    int fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
107
44
    std::cout <<"read open file: " << fd <<std::endl;
108
44
    read(fd, buf, sizeof (buf));
109
44
    std::cout << "buf: " << buf << std::endl;
110
44
    close(fd);
111
44
    return (std::string(buf));
112
44
*/    std::string buf = "NULL";
113
44
    std::fstream fd;
114
44
    fd.open(path.c_str(), std::fstream::in | std::fstream::out | std::fstream::app);
115
44
116
44
    std::getline(fd,buf);
117
44
    return buf;
118
44
}
119
120
size_t useful_F_libs::WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
121
77
{
122
77
    ((std::string*)userp)->append((char*)contents, size * nmemb);
123
77
    return size * nmemb;
124
77
}
125
126
std::string useful_F_libs::find_tag(const std::string& temp)
127
56
{
128
56
    std::string value = "";
129
1.17k
    for (unsigned int i = 0; i<temp.size();++i){
130
1.17k
131
1.17k
        if (temp.at(i) =='>')
132
56
        {  int z = i+1;
133
168
            while (temp.at(z)!='<')
134
112
            {
135
112
                value+= temp.at(z);
136
112
                ++z;
137
112
            }
138
56
            break;
139
56
        }
140
1.17k
    }
141
56
    return value;
142
56
}
143
144
#ifndef BT_TEST
145
std::string useful_F_libs::httpPost(const std::string& url, int timeoutSeconds)
146
{
147
    CURL *curl;
148
    CURLcode res;
149
    std::string readBuffer;
150
    curl = curl_easy_init();
151
152
    if(curl) {
153
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeoutSeconds);
154
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
155
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, useful_F_libs::WriteCallback);
156
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
157
        res = curl_easy_perform(curl);
158
        /* Check for errors */
159
        if(res != CURLE_OK)
160
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
161
                    curl_easy_strerror(res));
162
163
        /* always cleanup */
164
        curl_easy_cleanup(curl);
165
    }
166
    curl_global_cleanup();
167
168
    return readBuffer;
169
}
170
171
std::string useful_F_libs::httpPost(const std::string& url)
172
{
173
    return useful_F_libs::httpPost(url, 10);
174
}
175
#endif
176
177
void useful_F_libs::downloadFile(const std::string& url, const std::string& path, int timeoutSeconds)
178
0
{
179
0
    CURL *curl;
180
0
    //CURLcode res;
181
0
182
0
    curl = curl_easy_init();
183
0
    if (curl) {
184
0
        FILE *fp = fopen(path.c_str(),"wb");
185
0
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeoutSeconds);
186
0
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
187
0
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
188
0
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
189
0
        //res = curl_easy_perform(curl);
190
0
        /* always cleanup */
191
0
        curl_easy_cleanup(curl);
192
0
        fclose(fp);
193
0
    }
194
0
}
195
196
12
std::string useful_F_libs::replaceAll(std::string str, const std::string& from, const std::string& to) {
197
12
    size_t start_pos = 0;
198
44
    while((start_pos = str.find(from, start_pos)) != std::string::npos) {
199
32
        str.replace(start_pos, from.length(), to);
200
32
        start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
201
32
    }
202
12
    return str;
203
12
}
204
std::string useful_F_libs::removeHtmlTag(std::string &data)
205
8
{
206
8
    data = useful_F_libs::replaceAll(data,"</dl>","\n");
207
8
208
8
    //data = useful_F::replaceAll(data,"    "," ");
209
8
    bool copy = true;
210
8
    std::string plainString = "";
211
8
    std::stringstream convertStream;
212
8
213
8
    // remove all xml tags
214
6.27k
    for (unsigned int i=0; i < data.length(); i++)
215
6.26k
    {
216
6.26k
        convertStream << data[i];
217
6.26k
218
6.26k
        if(convertStream.str().compare("<") == 0) copy = false;
219
6.19k
        else if(convertStream.str().compare(">") == 0)
220
76
        {
221
76
            copy = true;
222
76
            convertStream.str(std::string());
223
76
            continue;
224
76
        }
225
6.19k
226
6.19k
        if(copy) plainString.append(convertStream.str());
227
6.19k
228
6.19k
        convertStream.str(std::string());
229
6.19k
    }
230
8
231
8
    return plainString;
232
8
}
233
234
nlohmann::json useful_F_libs::getJson(const std::string& url)
235
16
{
236
16
    std::string str = useful_F_libs::httpPost(url);
237
16
    nlohmann::json jj = nlohmann::json::parse( str);
238
16
239
16
    return jj;
240
16
}
241
#endif
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/433MHz/RFLink/TEST/rflinkhandler_BT.cpp
Line
Count
Source
1
#include <gtest/gtest.h>
2
3
#include "../rflinkhandler.h"
4
#include "test_data.h"
5
6
class RFLinkHandler_Class_fixture : public ::testing::Test
7
{
8
public:
9
    thread_data test_my_data;
10
    config test_server_set;
11
    iDomSTATUS test_status;
12
    std::unique_ptr<RFLinkHandler> test_RFLink;
13
14
    void SetUp() final
15
20
    {
16
20
        test_server_set.TS_KEY = "key test";
17
20
        test_server_set.RFLinkBaudRate = "57600";
18
20
        test_server_set.RFLinkPort = "/dev/fakePortRS232";
19
20
        test_my_data.server_settings = &test_server_set;
20
20
        test_my_data.main_iDomStatus = &test_status;
21
20
        test_RFLink = std::make_unique<RFLinkHandler>(&test_my_data);
22
20
    }
23
    void TearDown() final
24
20
    {
25
20
    }
26
};
27
28
TEST_F(RFLinkHandler_Class_fixture, sendCommandAndWaitForReceive)
29
4
{
30
4
    test_RFLink->init();
31
4
    std::string k("msg_test;\n a=4:b=10;\n");
32
4
    SerialPi_set_recv_msg(k);
33
4
    std::string r = test_RFLink->sendCommandAndWaitForReceive("test command");
34
4
35
4
    EXPECT_STREQ(r.c_str(),"msg_test;");
36
4
    r = test_RFLink->sendCommandAndWaitForReceive("ok");
37
4
    EXPECT_STREQ(r.c_str()," a=4:b=10;");
38
4
}
39
40
TEST_F(RFLinkHandler_Class_fixture, port_does_not_exist)
41
4
{
42
4
    bool result =  test_RFLink->init();
43
4
    EXPECT_FALSE(result);
44
4
}
45
46
TEST_F(RFLinkHandler_Class_fixture, port_exist)
47
4
{
48
4
    test_server_set.RFLinkPort = "/dev/tty0";
49
4
    bool result =  test_RFLink->init();
50
4
    EXPECT_TRUE(result);
51
4
}
52
53
TEST_F(RFLinkHandler_Class_fixture, getValue)
54
4
{
55
4
    std::string m  = "20;90;Alecto V4;ID=557a;TEMP=0057;HUM=25;";
56
4
    EXPECT_STREQ(test_RFLink->getArgumentValueFromRFLinkMSG(m,"ID").c_str(),"557a");
57
4
    EXPECT_STREQ(test_RFLink->getArgumentValueFromRFLinkMSG(m,"TEMP").c_str(),"0057");
58
4
    EXPECT_THROW(test_RFLink->getArgumentValueFromRFLinkMSG(m,"test"),std::string);
59
4
}
60
61
TEST_F(RFLinkHandler_Class_fixture, readAndFlush)
62
4
{
63
4
    SerialPi_set_recv_msg("doTest;\n");
64
4
    std::string retStr = test_RFLink->readFromRS232();
65
4
    EXPECT_STREQ(retStr.c_str(), "doTest;");
66
4
67
4
    SerialPi_set_recv_msg("doTest2;\n");
68
4
    test_RFLink->flush();
69
4
    retStr = test_RFLink->readFromRS232();
70
4
    EXPECT_EQ(retStr.size(), 0);
71
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/433MHz/RFLink/rflinkhandler.cpp
Line
Count
Source
1
#include <unistd.h>
2
3
#include "rflinkhandler.h"
4
#include "../../functions/functions.h"
5
6
std::mutex RFLinkHandler::sm_RFLink_MUTEX;
7
std::string RFLinkHandler::sm_RFLink_BUFOR;
8
9
10
RFLinkHandler::RFLinkHandler(thread_data *my_data):
11
    serial_RFLink(my_data->server_settings->RFLinkPort)
12
208
{
13
208
    this->my_data = my_data;
14
208
#ifdef BT_TEST
15
208
    std::cout << "RFLinkHandler::RFLinkHandler()"<<std::endl;
16
208
#endif
17
208
}
18
19
bool RFLinkHandler::init()
20
12
{
21
12
    if( access( my_data->server_settings->RFLinkPort.c_str(), F_OK ) != -1 )
22
4
    {
23
4
        serial_RFLink.begin( std::stoi(my_data->server_settings->RFLinkBaudRate));
24
4
        log_file_mutex.mutex_lock();
25
4
        log_file_cout << INFO <<"otwarcie portu RS232 RFLink " << my_data->server_settings->RFLinkPort << "  "
26
4
                      <<my_data->server_settings->RFLinkBaudRate<<std::endl;
27
4
        log_file_mutex.mutex_unlock();
28
4
        return true;
29
4
    }
30
8
    else
31
8
    {
32
8
        log_file_mutex.mutex_lock();
33
8
        log_file_cout << ERROR <<"brak portu RS232 RFLink " << my_data->server_settings->RFLinkPort<<std::endl;
34
8
        log_file_mutex.mutex_unlock();
35
8
        return false;
36
8
    }
37
12
}
38
39
void RFLinkHandler::flush()
40
4
{
41
4
    serial_RFLink.flush();
42
4
}
43
44
void RFLinkHandler::sendCommand(std::string cmd)
45
4
{
46
4
    std::lock_guard<std::mutex> m_lock(sm_RFLink_MUTEX);
47
4
    cmd.append("\n\r"); // add NL & CR
48
4
    serial_RFLink.print(cmd.c_str());
49
4
}
50
51
std::string RFLinkHandler::sendCommandAndWaitForReceive(std::string cmd)
52
8
{
53
8
    std::lock_guard<std::mutex> m_lock(sm_RFLink_MUTEX);
54
8
    cmd.append("\n\r"); // add NL & CR
55
8
    serial_RFLink.print(cmd.c_str());
56
8
    return internalReadFromRS232();
57
8
}
58
59
std::string RFLinkHandler::readFromRS232()
60
8
{
61
8
    std::lock_guard<std::mutex> m_lock(sm_RFLink_MUTEX);
62
8
    return internalReadFromRS232();
63
8
}
64
65
std::string RFLinkHandler::internalReadFromRS232()
66
16
{
67
16
    std::string buf;
68
16
69
16
    if(serial_RFLink.available() > 0){
70
116
        while (true){
71
116
72
116
            char b = serial_RFLink.read();
73
116
            if (b == '\n'){
74
12
                break;
75
12
            }
76
104
            buf += b;
77
104
        }
78
12
    }
79
16
    return buf;
80
16
}
81
82
std::string RFLinkHandler::getArgumentValueFromRFLinkMSG(const std::string& msg, const std::string& var)
83
256
{
84
256
    std::string id;
85
256
86
256
    int pos = msg.find(var+"=");
87
256
    if (pos == -1 ){
88
76
        throw "argument \""+var+"\" not found";
89
76
    }
90
180
    if (msg.at(0) != '2' || msg.at(1) != '0'){
91
4
        throw WRONG_FORMAT();
92
4
    }
93
176
#ifdef BT_TEST
94
176
    std::cout << "znaleziono " << var <<" na pozycji " << pos <<std::endl;
95
176
#endif
96
176
97
1.06k
    for (int i = 1+pos+var.size();;++i ){
98
1.06k
        char t = msg.at(i);
99
1.06k
        if (t ==';'){
100
176
            break;
101
176
        }
102
884
        id += t;
103
884
    }
104
176
    return id;
105
176
106
176
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/433MHz/RFLink/rflinkhandler.h
Line
Count
Source
1
#ifndef RFLINKHANDLER_H
2
#define RFLINKHANDLER_H
3
4
#include <map>
5
#include <exception>
6
#include "../../SerialPi/serialpi.h"
7
#include "../../iDom_server_OOP.h"
8
9
class WRONG_FORMAT : public std::exception{
10
11
};
12
13
struct RFLink_DEV{
14
    int m_counter = 0;
15
    std::string msg;
16
36
    void counter(){
17
36
        ++m_counter;
18
36
    }
19
20
8
    std::string read(){
21
8
        return std::to_string(m_counter) + " \t"+ msg;
22
8
    }
23
};
24
25
class RFLinkHandler
26
{
27
    thread_data *my_data;
28
    SerialPi serial_RFLink;
29
30
public:
31
32
    static std::mutex sm_RFLink_MUTEX;
33
    static std::string sm_RFLink_BUFOR;
34
35
    unsigned int okTime = 0;
36
    unsigned int pingTime = 0;
37
    ////// temporarnie //////
38
    std::map<std::string, RFLink_DEV> rflinkMAP;
39
    /////////////////////////////
40
    RFLinkHandler(thread_data *my_data);
41
42
    bool init();
43
    // void run();
44
    void flush();
45
    void sendCommand(std::string cmd);
46
    std::string sendCommandAndWaitForReceive(std::string cmd);
47
    std::string readFromRS232();
48
private:
49
    std::string internalReadFromRS232();
50
//#ifdef BT_TEST
51
public:
52
//#endif
53
    static std::string getArgumentValueFromRFLinkMSG(const std::string &msg, const std::string &var);
54
};
55
56
#endif // RFLINKHANDLER_H
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/LCD_c/test/lcd_c_stub.cpp
Line
Count
Source
1
#include <iostream>
2
#include "../lcd_c.h"
3
4
220
void LCD_c::set_print_song_state(int i){
5
220
    std::cout << "LCD_c::set_print_song_state(int i)" << i <<std::endl;
6
220
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/RADIO_433_eq/radio_433_eq.cpp
Line
Count
Source (jump to first uncovered line)
1
#include <iostream>
2
#include <fstream>
3
#include <sstream>
4
#include "radio_433_eq.h"
5
6
RADIO_SWITCH::RADIO_SWITCH(thread_data *my_data, const RADIO_EQ_CONFIG &cfg, RADIO_EQ_TYPE type):
7
    main433MHz(my_data)
8
3.97k
{
9
3.97k
    puts("RADIO_SWITCH::RADIO_SWITCH()");
10
3.97k
    RADIO_EQ::m_my_data = my_data;
11
3.97k
    RADIO_EQ::m_type = type;
12
3.97k
    RADIO_EQ::m_config = cfg;
13
3.97k
    m_sunrise = stringToState(cfg.sunrise);
14
3.97k
    m_sunset  = stringToState(cfg.sunset);
15
3.97k
}
16
17
RADIO_SWITCH::~RADIO_SWITCH()
18
3.97k
{
19
3.97k
    puts("RADIO_SWITCH::~RADIO_SWITCH()");
20
3.97k
}
21
22
void RADIO_SWITCH::on()
23
56
{
24
56
    if(RADIO_EQ::m_config.onCode != "null")
25
44
    {
26
44
        main433MHz.sendCode(RADIO_EQ::m_config.onCode);
27
44
        m_state = STATE::ON;
28
44
        RADIO_EQ::m_my_data->main_iDomStatus->setObjectState(RADIO_EQ::m_config.name, STATE::ON);
29
44
    }
30
12
    else {
31
12
        log_file_mutex.mutex_lock();
32
12
        log_file_cout << ERROR << RADIO_EQ::m_config.name << " switch -  zla konfiguracja kodu ON" << std::endl;
33
12
        log_file_mutex.mutex_unlock();
34
12
    }
35
56
}
36
37
void RADIO_SWITCH::off()
38
64
{
39
64
    if(RADIO_EQ::m_config.offCode != "null")
40
52
    {
41
52
        main433MHz.sendCode(RADIO_EQ::m_config.offCode);
42
52
        m_state = STATE::OFF;
43
52
        RADIO_EQ::m_my_data->main_iDomStatus->setObjectState(RADIO_EQ::m_config.name,STATE::OFF);
44
52
    }
45
12
    else {
46
12
        log_file_mutex.mutex_lock();
47
12
        log_file_cout << ERROR << RADIO_EQ::m_config.name << " switch -  zla konfiguracja kodu OFF" << std::endl;
48
12
        log_file_mutex.mutex_unlock();
49
12
    }
50
64
}
51
52
void RADIO_SWITCH::onFor15sec()
53
8
{
54
8
    if(RADIO_EQ::m_config.on15sec != "null")
55
4
    {
56
4
        main433MHz.sendCode(RADIO_EQ::m_config.on15sec);
57
4
        m_state = STATE::TEMPORARY;
58
4
        RADIO_EQ::m_my_data->main_iDomStatus->setObjectState(RADIO_EQ::m_config.name,STATE::TEMPORARY);
59
4
    }
60
4
    else {
61
4
        log_file_mutex.mutex_lock();
62
4
        log_file_cout << ERROR << RADIO_EQ::m_config.name << " switch - zla konfiguracja kodu ON for 15s" << std::endl;
63
4
        log_file_mutex.mutex_unlock();
64
4
    }
65
8
}
66
67
void RADIO_SWITCH::onSunrise()
68
40
{
69
40
    if(m_sunrise == STATE::ON ){
70
4
        on();
71
4
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " ON due to sunrise");
72
4
    }
73
36
    else if(m_sunrise == STATE::OFF){
74
12
        off();
75
12
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " OFF due to sunrise");
76
12
    }
77
40
}
78
79
void RADIO_SWITCH::onSunset()
80
44
{
81
44
    if(m_sunset == STATE::ON ){
82
12
        on();
83
12
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " ON due to sunset");
84
12
    }
85
32
    else if(m_sunset == STATE::OFF){
86
4
        off();
87
4
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " OFF due to sunset");
88
4
    }
89
44
}
90
91
void RADIO_SWITCH::onLockHome()
92
28
{
93
28
    if (m_config.lock == "ON")
94
4
    {
95
4
        on();
96
4
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " ON due to 433MHz button pressed");
97
4
    }
98
24
    else if(m_config.lock == "OFF")
99
8
    {
100
8
        off();
101
8
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " OFF due to 433MHz button pressed");
102
8
    }
103
28
}
104
105
void RADIO_SWITCH::onUnlockHome()
106
28
{
107
28
    if (m_config.unlock == "ON")
108
8
    {
109
8
        on();
110
8
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " ON due to 433MHz button pressed");
111
8
    }
112
20
    else if (m_config.unlock == "OFF")
113
4
    {
114
4
        off();
115
4
        m_my_data->myEventHandler.run("iDom")->addEvent("radio switch "+RADIO_EQ::m_config.name + " OFF due to 433MHz button pressed");
116
4
    }
117
28
}
118
119
STATE RADIO_SWITCH::getState()
120
1.53k
{
121
1.53k
    return m_state;
122
1.53k
}
123
124
std::string RADIO_SWITCH::getName()
125
2.16k
{
126
2.16k
    return RADIO_EQ::m_config.name;
127
2.16k
}
128
129
std::string RADIO_SWITCH::getID()
130
460
{
131
460
    return RADIO_EQ::m_config.ID;
132
460
}
133
134
void RADIO_SWITCH::setCode(RADIO_EQ_CONFIG cfg)
135
3.98k
{
136
3.98k
    RADIO_EQ::m_config.onCode = cfg.onCode;
137
3.98k
    RADIO_EQ::m_config.offCode = cfg.offCode;
138
3.98k
    RADIO_EQ::m_config.on15sec = cfg.on15sec;
139
3.98k
    RADIO_EQ::m_config.type = cfg.type;
140
3.98k
    RADIO_EQ::m_config.lock = cfg.lock;
141
3.98k
    RADIO_EQ::m_config.unlock = cfg.unlock;
142
3.98k
    RADIO_EQ::m_config.name = cfg.name;
143
3.98k
144
3.98k
    if(cfg.sunset == "on"){
145
8
        m_sunset = STATE::ON;
146
8
    }
147
3.98k
    if(cfg.sunset == "off"){
148
4
        m_sunset = STATE::OFF;
149
4
    }
150
3.98k
    if(cfg.sunrise == "on"){
151
4
        m_sunrise = STATE::ON;
152
4
    }
153
3.98k
    if(cfg.sunrise == "off"){
154
8
        m_sunrise = STATE::OFF;
155
8
    }
156
3.98k
}
157
158
RADIO_EQ_CONTAINER::RADIO_EQ_CONTAINER(thread_data *my_data)
159
792
{
160
792
    puts("RADIO_EQ_CONTAINER::RADIO_EQ_CONTAINER()");
161
792
    this->my_data = my_data;
162
792
}
163
164
RADIO_EQ_CONTAINER::~RADIO_EQ_CONTAINER()
165
792
{
166
6.33k
    for(auto it = m_radioEqMap.begin(); it != m_radioEqMap.end(); ++it) {
167
5.54k
        delete it->second;
168
5.54k
    }
169
792
    puts("RADIO_EQ_CONTAINER::~RADIO_EQ_CONTAINER()");
170
792
}
171
172
void RADIO_EQ_CONTAINER::addRadioEq( RADIO_EQ_CONFIG cfg, RADIO_EQ_TYPE type)
173
5.56k
{
174
5.56k
    switch (type) {
175
5.56k
    case RADIO_EQ_TYPE::SWITCH:
176
3.97k
        m_radioEqMap.insert(std::make_pair(cfg.name, new RADIO_SWITCH(my_data, cfg, RADIO_EQ_TYPE::SWITCH) ) );
177
3.97k
        break;
178
5.56k
    case RADIO_EQ_TYPE::BUTTON:
179
796
        m_radioEqMap.insert(std::make_pair(cfg.name, new RADIO_BUTTON(my_data, cfg, RADIO_EQ_TYPE::BUTTON) ) );
180
796
        break;
181
5.56k
    case RADIO_EQ_TYPE::WEATHER_S:
182
788
        m_radioEqMap.insert(std::make_pair(cfg.name, new RADIO_WEATHER_STATION(my_data, cfg, RADIO_EQ_TYPE::WEATHER_S) ) );
183
788
        break;
184
5.56k
    default:
185
4
        break;
186
5.56k
    }
187
5.56k
}
188
189
void RADIO_EQ_CONTAINER::addRadioEq(RADIO_EQ_CONFIG cfg, const std::string& type)
190
24
{
191
24
    RADIO_EQ_TYPE ret = RADIO_EQ_TYPE::NONE;
192
24
    if(type == "SWITCH") ret = RADIO_EQ_TYPE::SWITCH;
193
12
    else if(type == "BUTTON") ret = RADIO_EQ_TYPE::BUTTON;
194
8
    else if(type == "WEATHER") ret = RADIO_EQ_TYPE::WEATHER_S;
195
8
    else if(type == "PIR") ret = RADIO_EQ_TYPE::PIR;
196
4
    else if(type == "GATE") ret = RADIO_EQ_TYPE::GATE;
197
4
    else throw WRONG_FORMAT();
198
20
    std::cout << " id ma : " << cfg.ID << std::endl;
199
20
    std::stoi(cfg.ID); //check ID is number
200
20
    addRadioEq(cfg,ret);
201
20
}
202
203
void RADIO_EQ_CONTAINER::deleteRadioEq(const std::string& name)
204
16
{
205
16
    delete m_radioEqMap[name];
206
16
    m_radioEqMap.erase(name);
207
16
    saveConfig(my_data->server_settings->radio433MHzConfigFile);
208
16
}
209
210
RADIO_EQ* RADIO_EQ_CONTAINER::getEqPointer(std::string name)
211
4.27k
{
212
4.27k
    auto m = m_radioEqMap.find(name);
213
4.27k
    if (m != m_radioEqMap.end()){
214
4.24k
        return (m->second);
215
4.24k
    }
216
24
    else
217
24
    {
218
24
        throw std::string("433MHz equipment not found "+name);
219
24
    }
220
0
}
221
222
std::vector<RADIO_SWITCH*> RADIO_EQ_CONTAINER::getSwitchPointerVector()
223
380
{
224
380
    std::vector<RADIO_SWITCH*> switchVector;
225
380
226
2.67k
    for (auto it : m_radioEqMap){
227
2.67k
        if (it.second->getType() == RADIO_EQ_TYPE::SWITCH){
228
1.91k
            switchVector.push_back(static_cast<RADIO_SWITCH*>(it.second));
229
1.91k
        }
230
2.67k
    }
231
380
    return switchVector;
232
380
}
233
234
std::vector<RADIO_BUTTON *> RADIO_EQ_CONTAINER::getButtonPointerVector()
235
920
{
236
920
    std::vector<RADIO_BUTTON*> buttonVector;
237
920
238
6.45k
    for (auto it : m_radioEqMap){
239
6.45k
        if (it.second->getType() == RADIO_EQ_TYPE::BUTTON){
240
928
            buttonVector.push_back(static_cast<RADIO_BUTTON*>(it.second));
241
928
        }
242
6.45k
    }
243
920
    return buttonVector;
244
920
}
245
246
std::vector<RADIO_WEATHER_STATION *> RADIO_EQ_CONTAINER::getWeather_StationPtrVector()
247
120
{
248
120
    std::vector<RADIO_WEATHER_STATION*> weatherStVe;
249
848
    for (auto it : m_radioEqMap){
250
848
        if (it.second->getType() == RADIO_EQ_TYPE::WEATHER_S){
251
120
            weatherStVe.push_back(static_cast<RADIO_WEATHER_STATION*>(it.second));
252
120
        }
253
848
    }
254
120
    return weatherStVe;
255
120
}
256
257
std::string RADIO_EQ_CONTAINER::listAllName()
258
92
{
259
92
    std::string allName;
260
92
261
740
    for(auto it = m_radioEqMap.begin(); it != m_radioEqMap.end(); ++it) {
262
648
        allName.append(it->first);
263
648
        allName.append("\t ID: ");
264
648
        allName.append( it->second->getID() );
265
648
        allName.append("\t state: ");
266
648
        allName.append(stateToString(it->second->getState() ));
267
648
        allName.append("\n");
268
648
    }
269
92
270
92
    return allName;
271
92
}
272
273
bool RADIO_EQ_CONTAINER::nameExist(const std::string& name)
274
56
{
275
56
    bool exist = false;
276
56
    if(m_radioEqMap.find(name) != m_radioEqMap.end())
277
20
    {
278
20
        exist = true;
279
20
    }
280
56
    return exist;
281
56
}
282
283
void RADIO_EQ_CONTAINER::loadConfig(const std::string& filePath)
284
792
{
285
792
    std::ifstream myfile (filePath);
286
792
    if (myfile.is_open())
287
792
    {
288
792
        m_radioEqMap.clear();
289
792
        nlohmann::json j;
290
792
        myfile >> j;
291
792
292
792
        RADIO_EQ_CONFIG cfg;
293
792
294
792
        try
295
792
        {
296
792
            nlohmann::json switchJson = j.at("SWITCH");
297
4.75k
            for (nlohmann::json::iterator it = switchJson.begin(); it != switchJson.end(); ++it)
298
3.96k
            {
299
3.96k
                nlohmann::json switchJson = it.value();
300
3.96k
                cfg.name = switchJson.at("name").get<std::string>();
301
3.96k
                cfg.ID   = switchJson.at("id").get<std::string>();
302
3.96k
                cfg.offCode = switchJson.at("OFF").get<std::string>();
303
3.96k
                cfg.onCode  = switchJson.at("ON").get<std::string>();
304
3.96k
                cfg.on15sec = switchJson.at("on15sec").get<std::string>();
305
3.96k
                cfg.sunrise = switchJson.at("sunrise").get<std::string>();
306
3.96k
                cfg.sunset  = switchJson.at("sunset").get<std::string>();
307
3.96k
                cfg.lock    = switchJson.at("lock").get<std::string>();
308
3.96k
                cfg.unlock  = switchJson.at("unlock").get<std::string>();
309
3.96k
                cfg.type    = switchJson.at("type").get<std::string>();
310
3.96k
                addRadioEq(cfg,RADIO_EQ_TYPE::SWITCH);
311
3.96k
                dynamic_cast<RADIO_SWITCH*>(getEqPointer(cfg.name))->setCode(cfg);
312
3.96k
            }
313
792
        }
314
792
        catch(...)
315
792
        {
316
0
            log_file_mutex.mutex_lock();
317
0
            log_file_cout << DEBUG << "no SWITCH equipment in config" << std::endl;
318
0
            log_file_mutex.mutex_unlock();
319
0
        }
320
792
        try
321
792
        {
322
792
            nlohmann::json buttonJson = j.at("BUTTON");
323
1.58k
            for (nlohmann::json::iterator it = buttonJson.begin(); it != buttonJson.end(); ++it)
324
792
            {
325
792
                nlohmann::json buttonJson = it.value();
326
792
                cfg.name = buttonJson.at("name").get<std::string>();
327
792
                cfg.ID   = buttonJson.at("id").get<std::string>();
328
792
                cfg.offCode = buttonJson.at("OFF").get<std::string>();
329
792
                cfg.onCode  = buttonJson.at("ON").get<std::string>();
330
792
                cfg.type    = buttonJson.at("type").get<std::string>();
331
792
                addRadioEq(cfg,RADIO_EQ_TYPE::BUTTON);
332
792
            }
333
792
        }
334
792
        catch(...)
335
792
        {
336
0
            log_file_mutex.mutex_lock();
337
0
            log_file_cout << DEBUG << "no BUTTONs equipment in config" << std::endl;
338
0
            log_file_mutex.mutex_unlock();
339
0
#ifdef BT_TEST
340
0
            std::cout << "no BUTTONs equipment in config" <<std::endl;
341
0
#endif
342
0
        }
343
792
344
792
        try
345
792
        {
346
792
            nlohmann::json weatherJson= j.at("WEATHER");
347
1.58k
            for (nlohmann::json::iterator it = weatherJson.begin(); it != weatherJson.end(); ++it)
348
788
            {
349
788
                nlohmann::json weatherJson = it.value();
350
788
                cfg.name = weatherJson.at("name").get<std::string>();
351
788
                cfg.ID   = weatherJson.at("id").get<std::string>();
352
788
                cfg.type = weatherJson.at("type").get<std::string>();
353
788
                addRadioEq(cfg,RADIO_EQ_TYPE::WEATHER_S);
354
788
            }
355
792
        }
356
792
        catch(...)
357
792
        {
358
4
            log_file_mutex.mutex_lock();
359
4
            log_file_cout << DEBUG << "no WEATHER STAIONs equipment in config" << std::endl;
360
4
            log_file_mutex.mutex_unlock();
361
4
#ifdef BT_TEST
362
4
            std::cout << "no WEATHER STAIONs equipment in config" <<std::endl;
363
4
#endif
364
4
        }
365
792
366
792
        myfile.close();
367
792
    }
368
0
    else std::cout << "Unable to open file";
369
792
}
370
371
void RADIO_EQ_CONTAINER::saveConfig(const std::string& filePath)
372
40
{
373
40
    nlohmann::json switchJson;
374
40
    nlohmann::json buttonJson;
375
40
    nlohmann::json weatherJson;
376
40
377
40
    std::vector<RADIO_SWITCH*> vSwitch = getSwitchPointerVector();
378
40
    for(auto s : vSwitch)
379
204
    {
380
204
        switchJson[s->getName()] = s->m_config.getJson();
381
204
    }
382
40
383
40
    std::vector<RADIO_BUTTON*> vButton = getButtonPointerVector();
384
40
    for (auto s : vButton)
385
44
    {
386
44
        buttonJson[s->getName()] = s->m_config.getJson();
387
44
    }
388
40
389
40
    std::vector<RADIO_WEATHER_STATION *> vWeather = getWeather_StationPtrVector();
390
40
    for(auto s : vWeather)
391
40
    {
392
40
        weatherJson[s->getName()] = s->m_config.getJson();
393
40
    }
394
40
395
40
    m_configJson["SWITCH"] = switchJson;
396
40
    m_configJson["BUTTON"] = buttonJson;
397
40
    m_configJson["WEATHER"] = weatherJson;
398
40
    // write prettified JSON to another file
399
40
    std::ofstream o(filePath);
400
40
    o << std::setw(4) << m_configJson << std::endl;
401
40
}
402
403
std::string RADIO_EQ_CONTAINER::showConfig(const std::string &filePath)
404
4
{
405
4
    std::string ret = "can not open file ";
406
4
    ret.append(filePath);
407
4
408
4
    std::ifstream myfile (filePath);
409
4
    if (myfile.is_open())
410
4
    {
411
4
        nlohmann::json j;
412
4
        myfile >> j;
413
4
414
4
        ret = j.dump(4);
415
4
    }
416
4
    return ret;
417
4
}
418
419
RADIO_EQ::RADIO_EQ()
420
5.55k
{
421
5.55k
    this->m_my_data = std::nullptr_t();
422
5.55k
    puts("RADIO_EQ::RADIO_EQ()");
423
5.55k
}
424
425
RADIO_EQ::~RADIO_EQ()
426
5.55k
{
427
5.55k
    puts("RADIO_EQ::~RADIO_EQ()");
428
5.55k
}
429
430
RADIO_EQ_TYPE RADIO_EQ::getType()
431
9.98k
{
432
9.98k
    return m_type;
433
9.98k
}
434
435
RADIO_WEATHER_STATION::RADIO_WEATHER_STATION(thread_data *my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type)
436
788
{
437
788
    puts("RADIO_WEATHER_STATION::RADIO_WEATHER_STATION()");
438
788
    RADIO_EQ::m_my_data = my_data;
439
788
    RADIO_EQ::m_type = type;
440
788
    RADIO_EQ::m_config = cfg;
441
788
}
442
443
RADIO_WEATHER_STATION::~RADIO_WEATHER_STATION()
444
788
{
445
788
    puts("RADIO_WEATHER_STATION::~RADIO_WEATHER_STATION()");
446
788
}
447
448
STATE RADIO_WEATHER_STATION::getState()
449
92
{
450
92
    return m_state;
451
92
}
452
453
std::string RADIO_WEATHER_STATION::getName()
454
40
{
455
40
    return RADIO_EQ::m_config.name;
456
40
}
457
458
std::string RADIO_WEATHER_STATION::getID()
459
140
{
460
140
    return RADIO_EQ::m_config.ID;
461
140
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/RADIO_433_eq/radio_433_eq.h
Line
Count
Source (jump to first uncovered line)
1
#ifndef RADIO_SWITCH_H
2
#define RADIO_SWITCH_H
3
#include <gtest/gtest.h>
4
#include <gmock/gmock.h>
5
#include <map>
6
#include "../iDomStatus/idomstatus.h"
7
#include "../433MHz/RFLink/rflinkhandler.h"
8
9
#include "../433MHz/rc_433mhz.h"
10
#include "json.hpp"
11
12
struct WEATHER_STRUCT{
13
private:
14
    unsigned long int m_counter = 0;
15
protected:
16
    unsigned int m_humidity = 0;
17
    double m_temperature = 0.0;
18
    unsigned int m_barometricPressure = 0;
19
public:
20
16
    unsigned int getHumidity(){ return m_humidity; }
21
28
    double getTemperature(){ return m_temperature; }
22
12
    unsigned int getBarometricPressure(){ return m_barometricPressure; }
23
8
    std::string getDataString(){
24
8
        return "data: "+std::to_string(m_counter)+"\n"+"Humidity=" + std::to_string(getHumidity()) +"%\n"+
25
8
                "temperature= " + to_string_with_precision(getTemperature()) + "c\n"+
26
8
                "Pressure= " + std::to_string(getBarometricPressure())+ "kPa\n";
27
8
    }
28
29
20
    void putData(std::string data){
30
20
        std::string tempStr;
31
20
        int t = 0;
32
20
        ++m_counter;
33
20
        try{
34
20
            m_humidity = std::stoi( RFLinkHandler::getArgumentValueFromRFLinkMSG(data, "HUM") );
35
20
        }
36
20
        catch (...){ }
37
20
        try{
38
20
            m_barometricPressure = std::stoi( RFLinkHandler::getArgumentValueFromRFLinkMSG(data, "BARO") );
39
20
        }
40
20
        catch (...){ }
41
20
        try{
42
20
            tempStr = RFLinkHandler::getArgumentValueFromRFLinkMSG(data, "TEMP");
43
20
            std::stringstream ss;
44
20
            ss << std::hex << tempStr.substr(tempStr.size()-3,tempStr.size());
45
20
            ss >> t;
46
20
            m_temperature = t / 10.0;
47
20
            if(tempStr.at(0) == '8'){
48
8
                m_temperature *= -1.0;
49
8
            }
50
20
        }
51
20
        catch (...){ }
52
20
        //std::cout << "DUPA: "<<data<<" temp=" << m_temperature<< " hum="<<m_humidity<< std::endl;
53
20
    }
54
};
55
56
enum class RADIO_EQ_TYPE{
57
    SWITCH = 1,
58
    PIR,
59
    GATE,
60
    BUTTON,
61
    WEATHER_S,
62
    NONE
63
};
64
struct RADIO_EQ_CONFIG{
65
    std::string name = "NULL";
66
    std::string ID   = "NULL";
67
    std::string type = "NULL";
68
    std::string onCode  = "NULL";
69
    std::string offCode = "NULL";
70
    std::string on15sec = "NULL";
71
    std::string sunrise = "NULL";
72
    std::string sunset  = "NULL";
73
    std::string lock   = "NULL";
74
    std::string unlock = "NULL";
75
    void set(std::string type,
76
             std::string name,
77
             std::string ID,
78
             std::string onCode = "null",
79
             std::string offCode = "null",
80
             std::string on15sec = "null",
81
             std::string sunrise = "null",
82
             std::string sunset = "null",
83
             std::string lock = "null",
84
24
             std::string unlock = "null"){
85
24
        this->name = name;
86
24
        this->ID   = ID;
87
24
        this->type = type;
88
24
        this->onCode  = onCode;
89
24
        this->offCode = offCode;
90
24
        this->on15sec = on15sec;
91
24
        this->sunrise = sunrise;
92
24
        this->sunset  = sunset;
93
24
        this->lock   = lock;
94
24
        this->unlock = unlock;
95
24
    }
96
97
288
    nlohmann::json getJson(){
98
288
        nlohmann::json jj;
99
288
        jj["name"]  = name;
100
288
        jj["id"]    = ID;
101
288
        jj["type"]  = type;
102
288
        jj["ON"]    = onCode;
103
288
        jj["OFF"]   = offCode;
104
288
        jj["on15sec"] = on15sec;
105
288
        jj["sunrise"] = sunrise;
106
288
        jj["sunset"]  = sunset;
107
288
        jj["lock"]   = lock;
108
288
        jj["unlock"] = unlock;
109
288
        return jj;
110
288
    }
111
};
112
113
class RADIO_EQ{
114
public:
115
    RADIO_EQ();
116
    virtual ~RADIO_EQ();
117
    virtual STATE getState() = 0;
118
    virtual std::string getName() = 0;
119
    virtual std::string getID() = 0;
120
    virtual RADIO_EQ_TYPE getType();
121
protected:
122
    thread_data *m_my_data;
123
    RADIO_EQ_TYPE m_type;
124
public:
125
    RADIO_EQ_CONFIG m_config;
126
};
127
class RADIO_WEATHER_STATION: public RADIO_EQ
128
{
129
    STATE m_state = STATE::UNDEFINE;
130
131
public:
132
    RADIO_WEATHER_STATION(thread_data * my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type);
133
    ~RADIO_WEATHER_STATION();
134
    STATE getState();
135
    std::string getName();
136
    std::string getID();
137
    // data
138
    WEATHER_STRUCT data;
139
};
140
class RADIO_BUTTON: public RADIO_EQ
141
{
142
    STATE m_state = STATE::UNDEFINE;
143
144
public:
145
    RADIO_BUTTON(thread_data * my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type);
146
    ~RADIO_BUTTON();
147
    STATE getState();
148
    void setState(STATE s);
149
    std::string getName();
150
    std::string getID();
151
};
152
153
class RADIO_SWITCH: public RADIO_EQ
154
{
155
#ifdef BT_TEST
156
public:
157
#endif
158
    RC_433MHz main433MHz;
159
    STATE m_state = STATE::UNDEFINE;
160
public:
161
    RADIO_SWITCH(thread_data * my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type);
162
    ~RADIO_SWITCH();
163
    void on();
164
    void off();
165
    void onFor15sec();
166
    void onSunrise();
167
    void onSunset();
168
    void onLockHome();
169
    void onUnlockHome();
170
    STATE getState();
171
    std::string getName();
172
    std::string getID();
173
    void setCode(RADIO_EQ_CONFIG cfg);
174
    STATE m_sunrise = STATE::UNDEFINE;
175
    STATE m_sunset  = STATE::UNDEFINE;
176
};
177
178
class RADIO_EQ_CONTAINER
179
{
180
    std::map <std::string, RADIO_EQ* > m_radioEqMap;
181
    thread_data * my_data;
182
    nlohmann::json m_configJson;
183
public:
184
    RADIO_EQ_CONTAINER(thread_data * my_data);
185
    virtual ~RADIO_EQ_CONTAINER();
186
    void addRadioEq(RADIO_EQ_CONFIG cfg, RADIO_EQ_TYPE type);
187
    void addRadioEq(RADIO_EQ_CONFIG cfg, const std::string& type);
188
    void deleteRadioEq(const std::string &name);
189
    virtual RADIO_EQ* getEqPointer(std::string name);
190
    std::vector<RADIO_SWITCH*> getSwitchPointerVector();
191
    std::vector<RADIO_BUTTON*> getButtonPointerVector();
192
    std::vector<RADIO_WEATHER_STATION *> getWeather_StationPtrVector();
193
    std::string listAllName();
194
    bool nameExist(const std::string &name);
195
    void loadConfig(const std::string &filePath);
196
    void saveConfig(const std::string &filePath);
197
    std::string showConfig(const std::string &filePath);
198
};
199
200
class RADIO_EQ_CONTAINER_STUB : public RADIO_EQ_CONTAINER
201
{
202
    thread_data * k;
203
public:
204
0
    RADIO_EQ_CONTAINER_STUB(thread_data * k):RADIO_EQ_CONTAINER(k){this->k = k;}
205
206
0
    virtual ~RADIO_EQ_CONTAINER_STUB(){puts("~RADIO_EQ_CONTAINER_STUB()");}
207
    MOCK_METHOD1(getEqPointer, RADIO_EQ*(std::string name));
208
};
209
210
#endif // RADIO_SWITCH_H
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/RADIO_433_eq/radio_button.cpp
Line
Count
Source
1
#include "radio_433_eq.h"
2
/*
3
 * Najpierw możliwe do uzyskania funkcje załączania
4
5
    Załączenie chwilowe (momentary) - przekaźnik jest załączony tak długo jak długo naciskany jest klawisz pilota - nadawany kod
6
    Przełącznik (toggle) - przekaźnik jest załączany /wyłączany przy kolejnych naciśnięciach tego samego klawisza - nadajemy ten sam kod
7
    Włącz/wyłącz (latched) - przekaźnik jest załączany jednym kodem a wyłączany innym
8
    Włącznik czasowy 5 sek - po naciśnięciu pilota następuje załączenie przekaźnika na czas 5 sek
9
    Włącznik czasowy 10 sek - załączenie na czas 10 sek
10
    Włącznik czasowy 15 sek - załączenie na czas 15 sek
11
12
Programowanie
13
Niby opisane jest to na stronach dostawców - ale nie do końca - więc pełen opis programowania. Zalecane rozpoczęcie od punktu 8 - KASOWANIE
14
15
    Załączenie chwilowe (momentary) - naciskamy 1x przycisk programowania (potwierdzenie naciśnięcia krótkim błyskiem LED). LED po chwili włącza się na stałe na 8-10 sek. W tym czasie układ gotowy jest na przyjęcie nowego kodu. Wysłany kod zapamiętany jest w pamięci a potwierdzeniem tego jest podwójne "mrugnięcie" LEDa. LED gaśnie . Koniec procedury.
16
    Przełącznik (toggle) - naciskamy 2 x przycisk programowania. Dalej jak w pkt. 1
17
    Włącz/wyłącz (latched) - naciskamy 3 x przycisk programowania (potwierdzenie naciśnięcia krótkim błyskiem LED). LED po chwili włącza się na stałe na 8-10 sek. W tym czasie układ gotowy jest na przyjęcie nowego kodu. Wysłany kod zapamiętany jest w pamięci a potwierdzeniem tego jest podwójne "mrugnięcie" LEDa. LED pozostaje włączony Układ czeka na odbiór drugiego kodu. Po jego wysłaniu jest znowu podwójne "mrugnięcie" LEDa. LED gaśnie. Koniec procedury.
18
    Włącznik czasowy 5 sek - naciskamy 4 x przycisk programowania. Dalej jak w pkt. 1
19
    Włącznik czasowy 10 sek - naciskamy 5 x przycisk programowania. Dalej jak w pkt. 1
20
    Włącznik czasowy 15 sek - naciskamy 6 x przycisk programowania. Dalej jak w pkt. 1
21
    Włącznik czasowy 15 sek - naciskamy 7 x przycisk programowania. Dalej jak w pkt. 1
22
     KASOWANIE - usuwanie z pamięci wszystkich kodów. Nacisnąć 8 x przycisk. Każde naciśniecie sygnalizowane jest błyśnięciem. Po 8 naciśnięciu następują trzy mignięcia i pamięć kodów jest wyzerowana. Można też skasować pamięć naciskając przycisk raz przez ok 8 sek . Po puszczeniu przycisku LED zapali się na ok 3-4 sek i zgaśnie. Efekt działania ten sam.
23
24
Wszystkie te funkcje działają równolegle bo układ może zapamiętać do 50 kodów! Dodatkowo w trybie włącznika czasowego można skrócić czas załączenia poprzez wysłanie kodu WYŁĄCZ z wcześniej ustawionej funkcji latched.
25
 */
26
RADIO_BUTTON::RADIO_BUTTON(thread_data *my_data, const RADIO_EQ_CONFIG& cfg, RADIO_EQ_TYPE type)
27
796
{
28
796
    puts("RADIO_BUTTON::RADIO_BUTTON()");
29
796
    RADIO_EQ::m_my_data = my_data;
30
796
    RADIO_EQ::m_type = type;
31
796
    RADIO_EQ::m_config = cfg;
32
796
}
33
34
RADIO_BUTTON::~RADIO_BUTTON()
35
796
{
36
796
    puts("RADIO_BUTTON::~RADIO_BUTTON()");
37
796
}
38
39
STATE RADIO_BUTTON::getState()
40
96
{
41
96
    return m_state;
42
96
}
43
44
void RADIO_BUTTON::setState(STATE s)
45
24
{
46
24
    m_state = s;
47
24
}
48
49
std::string RADIO_BUTTON::getName()
50
48
{
51
48
    return RADIO_EQ::m_config.name;
52
48
}
53
54
std::string RADIO_BUTTON::getID()
55
156
{
56
156
    return RADIO_EQ::m_config.ID;
57
156
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/RADIO_433_eq/test/radio_433_test.cpp
Line
Count
Source
1
#include <gtest/gtest.h>
2
#include <gmock/gmock.h>
3
#include "../radio_433_eq.h"
4
#include "../../iDomTools/test/iDomTools_fixture.h"
5
6
RC_433MHz::RC_433MHz(thread_data *test_my_data)
7
3.97k
{
8
3.97k
    this->m_my_data = test_my_data;
9
3.97k
}
10
void RC_433MHz::sendCode(const std::string& code)
11
100
{
12
100
    std::cout << "sendCode(): " << code << std::endl;
13
100
}
14
15
class Switch_Class_fixture : public iDomTOOLS_ClassTest
16
{
17
18
};
19
TEST_F(Switch_Class_fixture, getSwitchPointerVector)
20
4
{
21
4
    auto v = test_rec->getSwitchPointerVector();
22
4
    EXPECT_EQ(v.size(),5);
23
4
}
24
25
TEST_F(Switch_Class_fixture, getButtonPointerVector)
26
4
{
27
4
    auto v = test_rec->getButtonPointerVector();
28
4
    EXPECT_EQ(v.size(),1);
29
4
}
30
31
TEST_F(Switch_Class_fixture, switch_alarm_on)
32
4
{
33
4
    RADIO_SWITCH* ptr = dynamic_cast<RADIO_SWITCH*>(test_rec->getEqPointer("ALARM"));
34
4
35
4
    EXPECT_EQ(ptr->getType(),RADIO_EQ_TYPE::SWITCH);
36
4
    puts("radio switch type");
37
4
    EXPECT_EQ(ptr->getState(),STATE::UNDEFINE);
38
4
    puts("radio switch state");
39
4
    ptr->on();
40
4
    EXPECT_EQ(ptr->getState(),STATE::ON);
41
4
    ptr->off();
42
4
    EXPECT_EQ(ptr->getState(),STATE::OFF);
43
4
    ptr->onSunset();
44
4
    EXPECT_EQ(ptr->getState(),STATE::OFF);
45
4
}
46
47
TEST_F(Switch_Class_fixture, weatherStruct)
48
4
{
49
4
    WEATHER_STRUCT test_WS;
50
8
    EXPECT_DOUBLE_EQ(0.0, test_WS.getTemperature()) << "Tempertura zla";
51
4
52
4
    test_WS.putData("20;03;LaCrosse;ID=0506;TEMP=0137;");
53
8
    EXPECT_DOUBLE_EQ(31.1, test_WS.getTemperature()) << "Tempertura zla";
54
4
55
4
    test_WS.putData("20;03;LaCrosse;ID=0506;TEMP=8130;BARO=999;");
56
8
    EXPECT_DOUBLE_EQ(-30.4, test_WS.getTemperature()) << "Tempertura zla";
57
4
58
8
    EXPECT_EQ(999, test_WS.getBarometricPressure()) << "zle cisneinie";
59
4
60
4
    std::string retString = test_WS.getDataString();
61
4
    EXPECT_THAT(retString, testing::HasSubstr("Pressure= 999kPa"));
62
4
}
63
64
TEST_F(Switch_Class_fixture, read_write_config_json)
65
4
{
66
4
    auto v = test_rec->getSwitchPointerVector();
67
4
    EXPECT_EQ(v.size(),5);
68
4
    test_rec->saveConfig(test_server_set.radio433MHzConfigFile);
69
4
    v = test_rec->getSwitchPointerVector();
70
4
    EXPECT_EQ(v.size(),5);
71
4
}
72
73
TEST_F(Switch_Class_fixture, addUnexistsRadioEq)
74
4
{
75
4
    RADIO_EQ_CONFIG tCfg;
76
4
    tCfg.name = "cyniu";
77
4
    tCfg.ID = "8899";
78
4
    std::string _name = tCfg.name;
79
4
    EXPECT_FALSE(test_rec->nameExist(_name));
80
4
    test_rec->addRadioEq(tCfg, "PIR");
81
4
    EXPECT_FALSE(test_rec->nameExist(_name));
82
4
}
83
84
TEST_F(Switch_Class_fixture, add_and_erase_switch)
85
4
{
86
4
    RADIO_EQ_CONFIG tCfg;
87
4
    tCfg.name = "test";
88
4
    test_rec->addRadioEq(tCfg, RADIO_EQ_TYPE::SWITCH);
89
4
    auto v = test_rec->getSwitchPointerVector();
90
4
    EXPECT_EQ(v.size(),6);
91
4
    test_rec->saveConfig(test_server_set.radio433MHzConfigFile);
92
4
    v = test_rec->getSwitchPointerVector();
93
4
    EXPECT_EQ(v.size(),6);
94
4
95
4
    ///////delete
96
4
    test_rec->deleteRadioEq(tCfg.name);
97
4
    v = test_rec->getSwitchPointerVector();
98
4
    EXPECT_EQ(v.size(),5);
99
4
    test_rec->saveConfig(test_server_set.radio433MHzConfigFile);
100
4
    v = test_rec->getSwitchPointerVector();
101
4
    EXPECT_EQ(v.size(),5);
102
4
}
103
104
TEST_F(Switch_Class_fixture, loadConfig)
105
4
{
106
4
    RADIO_EQ_CONTAINER test_rec(&test_my_data);
107
4
    test_rec.loadConfig("/mnt/ramdisk/433_eq_conf_fake.json");
108
4
109
4
    EXPECT_FALSE(test_my_data.main_REC->nameExist("firstt"));
110
4
    EXPECT_TRUE(test_my_data.main_REC->nameExist("locker"));
111
4
112
4
    //test_rec.loadConfig("/mnt/ramdisk/433_eq_conf_fake.json");
113
4
}
114
115
TEST_F(Switch_Class_fixture, getUnexistPtr)
116
4
{
117
4
    EXPECT_THROW(test_my_data.main_REC->getEqPointer("kokos"),std::string);
118
4
}
119
120
TEST_F(Switch_Class_fixture, onLock_onUnlock_HOME)
121
4
{
122
4
    RADIO_EQ_CONFIG tCfg;
123
4
    tCfg.name = "cyniu";
124
4
    tCfg.ID = "8899";
125
4
    tCfg.lock = "ON";
126
4
127
4
    auto testRadioS = static_cast<RADIO_SWITCH*>(test_rec->getEqPointer("C"));
128
4
    testRadioS->setCode(tCfg);
129
4
    testRadioS->onLockHome();
130
4
    std::string eventStr = test_my_data.myEventHandler.run("iDom")->getEvent();
131
4
    EXPECT_THAT(eventStr, testing::HasSubstr("cyniu ON due to 433MHz button pressed"));
132
4
133
4
    tCfg.lock = "OFF";
134
4
    testRadioS->setCode(tCfg);
135
4
    testRadioS->onLockHome();
136
4
    eventStr = test_my_data.myEventHandler.run("iDom")->getEvent();
137
4
    EXPECT_THAT(eventStr, testing::HasSubstr("cyniu OFF due to 433MHz button pressed"));
138
4
139
4
    ////////////////////// unlock
140
4
    tCfg.unlock = "ON";
141
4
142
4
    testRadioS->setCode(tCfg);
143
4
    testRadioS->onUnlockHome();
144
4
     eventStr = test_my_data.myEventHandler.run("iDom")->getEvent();
145
4
    EXPECT_THAT(eventStr, testing::HasSubstr("cyniu ON due to 433MHz button pressed"));
146
4
147
4
    tCfg.unlock = "OFF";
148
4
    testRadioS->setCode(tCfg);
149
4
    testRadioS->onUnlockHome();
150
4
    eventStr = test_my_data.myEventHandler.run("iDom")->getEvent();
151
4
    EXPECT_THAT(eventStr, testing::HasSubstr("cyniu OFF due to 433MHz button pressed"));
152
4
}
153
154
TEST_F(Switch_Class_fixture, us_wrong_configurated_switch)
155
4
{
156
4
    auto testRadioS = static_cast<RADIO_SWITCH*>(test_rec->getEqPointer("C"));
157
4
    EXPECT_EQ(testRadioS->getState(), STATE::UNDEFINE);
158
4
    testRadioS->on();
159
4
    EXPECT_EQ(testRadioS->getState(), STATE::UNDEFINE);
160
4
    testRadioS->off();
161
4
    EXPECT_EQ(testRadioS->getState(), STATE::UNDEFINE);
162
4
    testRadioS->onFor15sec();
163
4
    EXPECT_EQ(testRadioS->getState(), STATE::UNDEFINE);
164
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/THERMOMETER_CONTAINER/test/thermometer_container_BT.cpp
Line
Count
Source
1
#include <gtest/gtest.h>
2
#include <gmock/gmock.h>
3
#include "../../iDomTools/test/iDomTools_fixture.h"
4
#include "../thermometer_container.h"
5
6
class Thermometer_container_fixture :  public ::testing::Test //public iDomTOOLS_ClassTest
7
{
8
public:
9
    THERMOMETER_CONTAINER testThermo;
10
    std::string termoName = "test_thermometer";
11
    std::vector<std::string> v;
12
13
    void SetUp() final
14
16
    {
15
16
        std::vector<std::string> v = {"10.2","11.22"};
16
16
        testThermo.add("inside");
17
16
        testThermo.add("outside");
18
16
        testThermo.updateAll(&v);
19
16
        v = {"20.2","21.22"};
20
16
        testThermo.updateAll(&v);
21
16
        std::cout << "temepratura inside" << testThermo.getTemp("inside") << std::endl;
22
16
        std::cout << "temepratura outside" << testThermo.getTemp("outside") << std::endl;
23
16
        testThermo.updateStats("inside");
24
16
        testThermo.updateStats("outside");
25
16
        std::cout << "rozmiar mapy termoetrow: " << testThermo.sizeOf() << std::endl;
26
16
        testThermo.showAll();
27
16
        puts("SetUp() Thermometer_container_fixture");
28
16
        puts("--------------------------------------");
29
16
    }
30
};
31
TEST_F(Thermometer_container_fixture, returnUnexistPTR)
32
4
{
33
4
    EXPECT_THROW(testThermo.returnThermometerPtr("fake"),std::string);
34
4
}
35
36
TEST_F(Thermometer_container_fixture, getStatsByName)
37
4
{
38
4
    std::string returnedStr = testThermo.getStatsByName("inside");
39
4
    std::cout << "zwrocono " << returnedStr << std::endl;
40
4
    EXPECT_THAT(returnedStr, testing::HasSubstr("min: 20.2"));
41
4
    EXPECT_THAT(returnedStr, testing::HasSubstr("max: 20.2"));
42
4
}
43
44
TEST_F(Thermometer_container_fixture, getLast2)
45
4
{
46
4
    std::cout << "rozmiar mapy termoetrow: " << testThermo.sizeOf() << std::endl;
47
4
    testThermo.updateStats("inside");
48
4
    testThermo.updateStats("outside");
49
4
    testThermo.showAll();
50
4
    v = {"44.4","45.45"};
51
4
    testThermo.updateAll(&v);
52
4
    testThermo.updateStats("inside");
53
4
    testThermo.updateStats("outside");
54
4
    std::string returnedStr = testThermo.getStatsByName("inside");
55
4
    std::cout << "zwrocono " << returnedStr <<"||"<< std::endl;
56
4
    auto v = testThermo.getLast2("inside");
57
4
    EXPECT_EQ(v.first, 20.2);
58
4
    EXPECT_EQ(v.second, 44.4);
59
4
}
60
61
TEST_F(Thermometer_container_fixture, isMoreDiff)
62
4
{
63
4
    std::cout << "rozmiar mapy termoetrow: " << testThermo.sizeOf() << std::endl;
64
4
    testThermo.updateStats("inside");
65
4
    testThermo.updateStats("outside");
66
4
    testThermo.showAll();
67
4
    v = {"24.4","45.45"};
68
4
    testThermo.updateAll(&v);
69
4
    testThermo.updateStats("inside");
70
4
    testThermo.updateStats("outside");
71
4
    EXPECT_FALSE(testThermo.isMoreDiff("inside",15.5));
72
4
    EXPECT_TRUE(testThermo.isMoreDiff("outside",15.5));
73
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/THERMOMETER_CONTAINER/thermometer_container.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "thermometer_container.h"
2
3
THERMOMETER *THERMOMETER_CONTAINER::returnThermometerPtr(const std::string& name)
4
1.23k
{
5
1.23k
    auto m = thermoMap.find(name);
6
1.23k
    if (m != thermoMap.end())
7
1.22k
        return &(m->second);
8
8
    else
9
8
    {
10
8
      throw std::string("thermometer not found!");
11
8
    }
12
0
}
13
14
THERMOMETER_CONTAINER::THERMOMETER_CONTAINER()
15
1.58k
{
16
1.58k
}
17
18
THERMOMETER::THERMOMETER(int iter):m_stats(iter)
19
3.16k
{
20
3.16k
}
21
22
void THERMOMETER_CONTAINER::add(const std::string &name)
23
3.16k
{
24
3.16k
    auto pair = std::make_pair(name, THERMOMETER(15));
25
3.16k
    thermoMap.insert(pair);
26
3.16k
}
27
28
void THERMOMETER_CONTAINER::setTemp(const std::string &name, double value)
29
192
{
30
192
    returnThermometerPtr(name)->m_thermometer.oldTemp = returnThermometerPtr(name)->m_thermometer.newTemp;
31
192
    returnThermometerPtr(name)->m_thermometer.newTemp = value;
32
192
}
33
34
double THERMOMETER_CONTAINER::getTemp(const std::string &name)
35
96
{
36
96
    return returnThermometerPtr(name)->m_thermometer.newTemp;
37
96
}
38
39
double THERMOMETER_CONTAINER::getOldTemp(const std::string &name)
40
64
{
41
64
    return returnThermometerPtr(name)->m_thermometer.oldTemp;
42
64
}
43
44
TEMPERATURE_STATE THERMOMETER_CONTAINER::getLastState(const std::string &name)
45
112
{
46
112
    return returnThermometerPtr(name)->m_thermometer.lastState;
47
112
}
48
49
void THERMOMETER_CONTAINER::setState(const std::string &name, TEMPERATURE_STATE state)
50
64
{
51
64
    returnThermometerPtr(name)->m_thermometer.lastState = state;
52
64
}
53
54
void THERMOMETER_CONTAINER::updateAll(std::vector<std::string> *vectorThermo)
55
96
{
56
96
    std::string in  = vectorThermo->at(0);
57
96
    std::string out = vectorThermo->at(1);
58
96
    setTemp("inside", std::stod(in));
59
96
    setTemp("outside",std::stod(out));
60
96
}
61
62
void THERMOMETER_CONTAINER::updateStats(const std::string &name)
63
112
{
64
112
    returnThermometerPtr(name)->m_stats.push_back(returnThermometerPtr(name)->m_thermometer.newTemp);
65
112
}
66
67
std::string THERMOMETER_CONTAINER::getStatsByName(const std::string &name)
68
16
{
69
16
    return returnThermometerPtr(name)->m_stats.stats();
70
16
}
71
72
bool THERMOMETER_CONTAINER::isMoreDiff(const std::string &name, double diff)
73
56
{
74
56
    return returnThermometerPtr(name)->m_stats.isMoreDiff(diff);
75
56
}
76
77
std::pair<double, double> THERMOMETER_CONTAINER::getLast2(const std::string &name)
78
20
{
79
20
    return returnThermometerPtr(name)->m_stats.getLast2();
80
20
}
81
82
int THERMOMETER_CONTAINER::sizeOf()
83
24
{
84
24
    return static_cast<int>(thermoMap.size());
85
24
}
86
87
void THERMOMETER_CONTAINER::showAll()
88
24
{
89
24
    for(auto n : thermoMap)
90
48
    {
91
48
        std::cout << n.first << " ";
92
48
    }
93
24
    std::cout << std::endl << "koniec prointowania w " << std::endl;
94
24
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/blockQueue/blockqueue.cpp
Line
Count
Source
1
#include "blockqueue.h"
2
#include "../iDom_server_OOP.h"
3
4
blockQueue::blockQueue()
5
528
{
6
528
}
7
std::mutex blockQueue::mutex_queue_char;
8
std::queue <MPD_COMMAND> blockQueue::_MPD_CommandQ;
9
void blockQueue::_add(MPD_COMMAND X)
10
276
{
11
276
    std::lock_guard <std::mutex> lock (mutex_queue_char);
12
276
    if(_MPD_CommandQ.size() < 10)
13
272
    {
14
272
        _MPD_CommandQ.push(X);
15
272
    }
16
4
    else
17
4
    {
18
4
        log_file_mutex.mutex_lock();
19
4
        log_file_cout << DEBUG << "za dużo danych w kolejce- nie dodaje "<< std::endl;
20
4
        log_file_mutex.mutex_unlock();
21
4
22
4
#ifdef BT_TEST
23
4
        std::string e = "za duzo w kolejce";
24
4
        throw e;
25
4
#endif
26
4
    }
27
272
}
28
29
MPD_COMMAND blockQueue::_get( )
30
200
{
31
200
    MPD_COMMAND temp = MPD_COMMAND::NULL_;
32
200
    std::lock_guard <std::mutex> lock (mutex_queue_char);
33
200
    if (_MPD_CommandQ.empty() == false){
34
188
        temp = _MPD_CommandQ.front();
35
188
        _MPD_CommandQ.pop();
36
188
    }
37
200
    return temp;
38
200
}
39
40
int blockQueue::_size()
41
150M
{
42
150M
    std::lock_guard <std::mutex> lock (mutex_queue_char);
43
150M
    return static_cast<int>(_MPD_CommandQ.size());
44
150M
}
45
46
void blockQueue::_clearAll()
47
268
{
48
268
     std::lock_guard <std::mutex> lock (mutex_queue_char);
49
352
     while (_MPD_CommandQ.empty() == false){
50
84
         _MPD_CommandQ.pop();
51
84
     }
52
268
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/blockQueue/test/blockqueue_BT.cpp
Line
Count
Source
1
#include <gtest/gtest.h>
2
#include "../blockqueue.h"
3
#include <thread>
4
#include <iostream>
5
6
class blockQueue_Class_fixture : public ::testing::Test
7
{
8
public:
9
16
    blockQueue_Class_fixture()  {  }
10
11
protected:
12
    blockQueue test_q;
13
14
    void SetUp() final
15
16
    {
16
16
        test_q._clearAll();
17
16
        std::cout << "blockQueue_Class_fixture SetUp" << std::endl;
18
16
    }
19
20
    void TearDown() final
21
16
    {
22
16
        std::cout << "blockQueue_Class_fixture TearDown" << std::endl;
23
16
    }
24
    static void getFromQ_thread()
25
4
    {
26
4
        blockQueue q;
27
9.77k
        while(q._size() == 0 )
28
9.77k
        {
29
9.77k
        }
30
4
        EXPECT_EQ(q._get(), MPD_COMMAND::STOP);
31
150M
        while(q._size() == 0 )
32
150M
        {
33
150M
        }
34
4
        EXPECT_EQ(q._get(), MPD_COMMAND::STOP);
35
4
    }
36
37
    static void putToQ_thread(MPD_COMMAND c)
38
4
    {
39
4
        blockQueue q;
40
4
        q._add(c);
41
4
        sleep(1);
42
4
        q._add(c);
43
4
    }
44
};
45
46
TEST_F(blockQueue_Class_fixture, main)
47
4
{
48
4
    test_q._clearAll();
49
4
    EXPECT_EQ(test_q._size(), 0);
50
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::NULL_);
51
4
    test_q._add(MPD_COMMAND::PLAY);
52
4
    EXPECT_EQ(test_q._size(), 1);
53
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PLAY);
54
4
    EXPECT_EQ(test_q._size(), 0);
55
4
}
56
57
TEST_F(blockQueue_Class_fixture, inThread)
58
4
{
59
4
    std::thread get(blockQueue_Class_fixture::getFromQ_thread);
60
4
    std::thread put(blockQueue_Class_fixture::putToQ_thread,MPD_COMMAND::STOP);
61
4
    get.join();
62
4
    put.join();
63
4
}
64
65
TEST_F(blockQueue_Class_fixture, allClear)
66
4
{
67
4
    EXPECT_EQ(test_q._size(), 0);
68
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::NULL_);
69
4
    test_q._add(MPD_COMMAND::PLAY);
70
4
    EXPECT_EQ(test_q._size(), 1);
71
4
    test_q._add(MPD_COMMAND::PLAY);
72
4
    EXPECT_EQ(test_q._size(), 2);
73
4
    test_q._clearAll();
74
4
    EXPECT_EQ(test_q._size(), 0);
75
4
}
76
77
TEST_F(blockQueue_Class_fixture, capacityExceeded)
78
4
{
79
4
    EXPECT_EQ(test_q._size(), 0);
80
4
81
44
    for (auto i = 0 ; i <10 ; ++i)
82
40
    {
83
40
      test_q._add(MPD_COMMAND::PLAY);
84
40
    }
85
4
86
4
    EXPECT_THROW(test_q._add(MPD_COMMAND::PLAY), std::string );
87
4
    test_q._clearAll();
88
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/c_connection/c_connection.cpp
Line
Count
Source (jump to first uncovered line)
1
#include <iostream>
2
#include "c_connection.h"
3
#include "../thread_functions/iDom_thread.h"
4
5
C_connection::C_connection (thread_data *my_data):c_socket(my_data->s_client_sock),
6
    c_from(my_data->from),recv_size(0)
7
32
{
8
32
    this -> pointer = &my_data->pointer;
9
32
    this -> my_data = my_data;
10
32
    this->m_encrypted = my_data->server_settings->encrypted;
11
32
    std::fill(std::begin(c_buffer),std::end(c_buffer),',');
12
32
    onStartConnection();
13
32
}
14
15
C_connection::~C_connection()
16
32
{
17
32
    if( mainCommandHandler != std::nullptr_t())
18
12
    {
19
12
        my_data->mainLCD->set_print_song_state(0);
20
12
        my_data->mainLCD->set_lcd_STATE(2);
21
12
        delete mainCommandHandler;
22
12
    }
23
32
    my_data->mainLCD->set_print_song_state(0);
24
32
    my_data->mainLCD->set_lcd_STATE(2);
25
32
26
32
    useful_F::sleep(3);
27
32
28
32
    shutdown(c_socket, SHUT_RDWR );
29
32
    //useful_F::clearThreadArray(my_data);
30
32
    iDOM_THREAD::stop_thread("connections TCP", my_data);
31
32
    puts("C_connection::~C_connection()");
32
32
}
33
34
int C_connection::c_send(int para)
35
4
{
36
4
    crypto(str_buf,m_encriptionKey,m_encrypted); //BUG - naprawic czytanie flagi z parametru klasy
37
4
    std::string len = std::to_string( str_buf.size());
38
4
    crypto(len,m_encriptionKey,m_encrypted);
39
4
    if(( send( c_socket, len.c_str() ,len.length(), para ) ) <= 0 )
40
4
    {
41
4
        return -1;
42
4
    }
43
0
    recv_size = recv( c_socket, c_buffer , MAX_buf, para );
44
0
45
0
    if(recv_size < 0 )
46
0
    {
47
0
        log_file_mutex.mutex_lock();
48
0
        log_file_cout << ERROR << "C_connection::c_send(int para) recv() error - " << strerror( errno ) << std::endl;
49
0
        log_file_mutex.mutex_unlock();
50
0
        return -1;
51
0
    }
52
0
    else if (recv_size == 0)
53
0
    {
54
0
        return -1;
55
0
    }
56
0
57
0
    auto len_send = str_buf.length();
58
0
59
0
    while (len_send > 0)
60
0
    {
61
0
        auto len_temp = send( c_socket, str_buf.c_str() ,str_buf.length(), para );
62
0
        if(len_temp <= 0 )
63
0
        {
64
0
            return -1;
65
0
        }
66
0
        len_send -= len_temp;
67
0
        str_buf.erase(0,len_temp);
68
0
    }
69
0
    return 0;
70
0
}
71
72
int C_connection::c_send(const std::string &command )
73
4
{
74
4
    str_buf = command;
75
4
    return c_send(0);
76
4
}
77
78
int C_connection::c_recv(int para)
79
4
{
80
4
    struct timeval tv;
81
4
    tv.tv_sec = 90;
82
4
    tv.tv_usec = 0;
83
4
    setsockopt(c_socket,SOL_SOCKET,SO_RCVTIMEO,(char*)&tv , sizeof(struct timeval));
84
4
85
4
    recv_size = recv(c_socket, c_buffer, MAX_buf, para);
86
4
87
4
    if(recv_size < 0)
88
4
    {
89
4
        log_file_mutex.mutex_lock();
90
4
        log_file_cout << ERROR << "C_connection::c_recv(int para) recv() error - " << strerror( errno ) << std::endl;
91
4
        log_file_mutex.mutex_unlock();
92
4
        return -1;
93
4
    }
94
0
    else if (recv_size == 0)
95
0
    {
96
0
        return -1;
97
0
    }
98
0
    return recv_size;
99
0
}
100
101
void C_connection::c_analyse(int recvSize)
102
12
{
103
12
    std::string buf;
104
12
105
12
    buf = c_read_buf(recvSize);
106
12
    my_data->myEventHandler.run("command")->addEvent(buf);
107
12
    std::vector <std::string> command;
108
12
    try{
109
12
    useful_F::tokenizer(command," \n,", buf);
110
12
    }
111
12
    catch (std::string& k){
112
4
        log_file_mutex.mutex_lock();
113
4
        log_file_cout << DEBUG << "brak komendy - " << k << std::endl;
114
4
        log_file_mutex.mutex_unlock();
115
4
        str_buf = "empty command";
116
4
        return;
117
4
    }
118
8
119
8
#ifdef BT_TEST
120
8
    std::cout << "komenda: " << str_buf << " command.size() " << command.size() << std::endl;
121
8
#endif
122
8
    str_buf = "unknown command\n";
123
8
124
8
    for(std::string t : command)
125
20
    {
126
20
        str_buf += t+" ";
127
20
    }
128
8
129
8
    str_buf = mainCommandHandler->run(command,my_data);
130
8
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/c_connection/c_connection.h
Line
Count
Source
1
#ifndef C_CONNECTION_H
2
#define C_CONNECTION_H
3
#include <mutex>
4
#include <unistd.h>
5
#include <iostream>
6
#include "../functions/functions.h"
7
#include "../CRON/cron.hpp"
8
#include "../functions/mpd_cli.h"
9
#include "../command/commandhandlerroot.h"
10
#include "../iDom_server_OOP.h"
11
12
constexpr int MAX_buf = 32768;
13
14
class C_connection
15
{
16
#ifdef BT_TEST
17
   friend class c_connection_fixture;
18
#endif
19
public:
20
    C_connection(thread_data *my_data);
21
    ~C_connection();
22
23
    thread_data *my_data;
24
    int c_socket;
25
    sockaddr_in c_from;
26
27
    char c_buffer[MAX_buf];
28
    int recv_size;
29
    struct s_pointer *pointer;
30
31
    int c_send(int para);
32
    int c_send(const std::string& command);
33
    int c_recv(int para);
34
    std::string c_read_buf(int recvSize);
35
    void c_analyse(int recvSize);
36
    void setEncriptionKey(const std::string& key);
37
    void setEncrypted(bool flag);
38
    commandHandler *mainCommandHandler = NULL;
39
    void onStartConnection();
40
    void onStopConnection();
41
    void cryptoLog(std::string &toEncrypt);
42
#ifdef BT_TEST
43
4
    std::string getStr_buf(){
44
4
        return str_buf;
45
4
    }
46
#endif
47
private:
48
    std::string str_buf;
49
    blockQueue char_queue;
50
    int counter = 0;
51
    std::string m_encriptionKey;
52
    bool m_encrypted;
53
    void crypto(std::string &toEncrypt, std::string key, bool encrypted);
54
};
55
56
#endif // C_CONNECTION_H
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/c_connection/c_connection2.cpp
Line
Count
Source
1
#include "c_connection.h"
2
#include <iostream>
3
4
std::string C_connection::c_read_buf (int recvSize)
5
12
{
6
12
    std::string str_buf;
7
136
    for (int i = 0; i < recvSize; ++i)
8
124
    {
9
124
        str_buf.push_back( c_buffer[i]);
10
124
    }
11
12
    crypto(str_buf,m_encriptionKey,m_encrypted);
12
12
    return str_buf;
13
12
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/c_connection/c_connection_node.cpp
Line
Count
Source
1
2
#include "c_connection.h"
3
#include <iostream>
4
5
//////// not used now
6
//void C_connection::c_start_master ()
7
//{
8
//    std::cout << " w pamieci jest " <<my_data->server_settings->AAS.size() <<" nodow\n";
9
//    for (unsigned int i =0; i<my_data->server_settings->AAS.size(); ++i )
10
//    {
11
//        std::cout << " jest ustawien id " << my_data->server_settings->AAS[i].id << std::endl;
12
//        std::cout << " jest ustawien ip " << my_data->server_settings->AAS[i].SERVER_IP << std::endl;
13
//    }
14
//        while (1)
15
//        {
16
//             //c_recv_master_to();
17
//             c_recv_send_master();
18
//             std::cout << " odebralem w masterze \n";
19
//             //c_send_master_to(c_bufor_tmp[16]);
20
//        }
21
//}
22
23
24
//void C_connection::c_recv_send_master()
25
//{
26
//    while (1)
27
//    {
28
//        std::this_thread::sleep_for( std::chrono::milliseconds(50) );
29
30
//        mutex_who.lock();
31
//        if (pointer->ptr_who[0] == my_data->server_settings->ID_server)
32
//        {
33
//            mutex_buf.lock();
34
35
//            for (int i =0; i < MAX_MSG_LEN; ++i )
36
//            {
37
//                 pointer->ptr_buf[i]-=1;
38
//            }
39
//            pointer->ptr_who[0] = pointer->ptr_who[1];
40
//            pointer->ptr_who[1] = my_data->server_settings->ID_server;
41
//            mutex_buf.unlock();
42
//        }
43
//         mutex_who.unlock();
44
//    } // end while
45
//}
46
47
void C_connection::setEncriptionKey(const std::string& key)
48
4
{
49
4
    m_encriptionKey = key;
50
4
}
51
52
void C_connection::setEncrypted(bool flag)
53
16
{
54
16
    m_encrypted = flag;
55
16
}
56
57
void C_connection::crypto(std::string &toEncrypt, std::string key, bool encrypted)
58
36
{
59
36
    if (!encrypted){
60
20
          return;
61
20
      }
62
16
    unsigned int keySize = key.size()-1;
63
16
#ifdef BT_TEST
64
16
    std::cout << "key: " << key << " size: " << key.size() << std::endl;
65
16
#endif
66
296
    for (unsigned int i = 0; i < toEncrypt.size (); i++)
67
280
    {
68
280
        if (keySize == 0)
69
24
            keySize = key.size()-1;
70
256
        else
71
256
            --keySize;
72
280
        toEncrypt[i] ^= key[keySize];
73
280
    }
74
16
}
75
76
void C_connection::onStartConnection()
77
32
{
78
32
//    log_file_mutex.mutex_lock();
79
32
//    log_file_cout << INFO<< "konstruuje nowy obiekt do komunikacj na gniezdzie " << c_socket << std::endl;
80
32
//    log_file_mutex.mutex_unlock();
81
32
}
82
83
void C_connection::onStopConnection()
84
4
{
85
4
    my_data->main_iDomTools->cameraLedOFF(my_data->server_settings->cameraLedOFF);
86
4
}
87
88
void C_connection::cryptoLog(std::string &toEncrypt)
89
8
{
90
8
    crypto(toEncrypt,m_encriptionKey,m_encrypted);
91
8
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/c_connection/test/c_connection_BT.cpp
Line
Count
Source (jump to first uncovered line)
1
#include <gtest/gtest.h>
2
#include "../../iDomTools/test/iDomTools_fixture.h"
3
4
#include "../c_connection.h"
5
6
class c_connection_fixture : public iDomTOOLS_ClassTest
7
{
8
public:
9
32
    c_connection_fixture():test_connection(std::nullptr_t()) {
10
32
    }
11
12
protected:
13
    std::unique_ptr<C_connection> test_connection;
14
    void SetUp() final
15
32
    {
16
32
        std::cout << "c_connection_fixture SetUp()" << std::endl;
17
32
        iDomTOOLS_ClassTest::SetUp();
18
32
        test_connection = std::make_unique<C_connection>(&test_my_data);
19
32
        test_connection->m_encriptionKey = "key";
20
32
        test_connection->m_encrypted = false;
21
32
        test_connection->c_socket = 0;
22
32
        std::array<Thread_array_struc,iDomConst::MAX_CONNECTION >test_ThreadArrayStruc;
23
32
24
352
        for (int i = 0 ; i < iDomConst::MAX_CONNECTION; i++)
25
320
            test_ThreadArrayStruc.at(i).thread_socket = i+1;
26
32
        test_ThreadArrayStruc.at(3).thread_socket = 0;
27
32
        test_my_data.main_THREAD_arr = &test_ThreadArrayStruc;
28
32
    }
29
    void TearDown() final
30
32
    {
31
32
        iDomTOOLS_ClassTest::TearDown();
32
32
        std::cout << "c_connection_fixture TearDown()" << std::endl;
33
32
    }
34
    void crypto_fixture(std::string &toEncrypt, std::string key)
35
8
    {
36
8
        test_connection->crypto(toEncrypt, std::move(key), true);
37
8
    }
38
};
39
40
TEST_F(c_connection_fixture, crypto)
41
4
{
42
4
    std::string key = "210116556";
43
4
    std::string test_msg = "kokosowa ksiezniczka";
44
4
    std::string toEncrypt = test_msg;
45
4
    crypto_fixture(toEncrypt, key);
46
4
47
84
    for(int i = 0; i < toEncrypt.size(); ++i)
48
80
    {
49
160
        EXPECT_NE(test_msg[i],toEncrypt[i]) << " niestety równe: " << toEncrypt[i]
50
160
                                            << " na indeksie: " << i;
51
80
    }
52
4
    std::cout << "wiadomość: " << test_msg << " zakodowane: "<< toEncrypt << std::endl;
53
4
    crypto_fixture(toEncrypt, key);
54
4
    std::cout << "wiadomość: " << test_msg << " odkodowane: "<< toEncrypt << std::endl;
55
8
    EXPECT_STREQ(toEncrypt.c_str(), test_msg.c_str()) << "wiadomosci nie są równe";
56
4
}
57
58
TEST_F(c_connection_fixture, c_analyse)
59
4
{
60
4
    commandHandlerRoot* chr = new commandHandlerRoot(&test_my_data);
61
4
    test_connection->mainCommandHandler = chr;
62
4
    int i = 0;
63
4
    std::string strMsg = "fake command";
64
4
    for (char n : strMsg)
65
48
        test_connection->c_buffer[i++] = n;
66
4
    test_connection->setEncrypted(false);
67
4
    test_connection->c_analyse(strMsg.size());
68
4
    EXPECT_THAT(test_my_data.myEventHandler.run("command")->getEvent()
69
4
                ,testing::HasSubstr(strMsg));
70
4
}
71
72
TEST_F(c_connection_fixture, c_recv)
73
4
{
74
4
    EXPECT_EQ(-1, test_connection->c_recv(1));
75
4
}
76
77
TEST_F(c_connection_fixture, c_send)
78
4
{
79
4
    EXPECT_EQ(-1, test_connection->c_send("test"));
80
4
}
81
82
TEST_F(c_connection_fixture, cryptoLog)
83
4
{
84
4
    std::string msg("tajna wiadomosc");
85
4
    std::string msgBackup(msg);
86
4
    test_connection->setEncriptionKey("key_test");
87
4
    test_connection->setEncrypted(true);
88
4
    ///////szyfrowanie
89
4
    test_connection->cryptoLog(msg);
90
4
    EXPECT_STRNE(msgBackup.c_str(), msg.c_str());
91
4
    std::cout << "ZASZUFROWANY: " << msg << std::endl;
92
4
    ////// deszyfracja
93
4
    test_connection->cryptoLog(msg);
94
4
    EXPECT_STREQ(msgBackup.c_str(), msg.c_str());
95
4
}
96
97
TEST_F(c_connection_fixture, onStopConnection)
98
4
{
99
4
    TEST_DATA::return_httpPost = "ok.\n";
100
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("cameraLED"),STATE::UNKNOWN);
101
4
    test_connection->onStopConnection();
102
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("cameraLED"),STATE::OFF);
103
4
}
104
105
TEST_F(c_connection_fixture, exitFlow)
106
4
{
107
4
    commandHandlerRoot* chr = new commandHandlerRoot(&test_my_data);
108
4
    test_connection->mainCommandHandler = chr;
109
4
110
4
    int i = 0;
111
4
    std::string strMsg = "program stop server";
112
4
    for (char n : strMsg)
113
76
        test_connection->c_buffer[i++] = n;
114
4
    test_connection->setEncrypted(false);
115
4
    EXPECT_THROW(test_connection->c_analyse(strMsg.size()),std::string );
116
4
}
117
118
TEST_F(c_connection_fixture, emptyCommand)
119
4
{
120
4
    commandHandlerRoot* chr = new commandHandlerRoot(&test_my_data);
121
4
    test_connection->mainCommandHandler = chr;
122
4
123
4
    int i = 0;
124
4
    std::string strMsg = "";
125
4
    for (char n : strMsg)
126
0
        test_connection->c_buffer[i++] = n;
127
4
    test_connection->setEncrypted(false);
128
4
    test_connection->c_analyse(strMsg.size());
129
4
    EXPECT_STREQ(test_connection->getStr_buf().c_str(), "empty command");
130
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/c_irda_logic/c_irda_logic.cpp
Line
Count
Source
1
#include "c_irda_logic.h"
2
#include "../iDom_server_OOP.h"
3
#include "../thread_functions/iDom_thread.h"
4
5
void c_irda_logic::irdaMPD(PILOT_KEY X)
6
40
{
7
40
    switch (X){
8
40
    case PILOT_KEY::KEY_POWER:
9
4
        mpd_queue._add(MPD_COMMAND::STOP);
10
4
        break;
11
40
    case PILOT_KEY::KEY_TV:
12
4
        mpd_queue._add(MPD_COMMAND::PLAY);
13
4
        break;
14
40
    case PILOT_KEY::KEY_VOLUMEDOWN:
15
4
        mpd_queue._add(MPD_COMMAND::VOLDOWN);
16
4
        break;
17
40
    case PILOT_KEY::KEY_VOLUMEUP:
18
4
        mpd_queue._add(MPD_COMMAND::VOLUP);
19
4
        break;
20
40
    case PILOT_KEY::KEY_AUDIO:
21
4
        mpd_queue._add(MPD_COMMAND::PAUSE);
22
4
        break;
23
40
    case PILOT_KEY::KEY_UP:
24
4
        mpd_queue._add(MPD_COMMAND::NEXT);
25
4
        break;
26
40
    case PILOT_KEY::KEY_DOWN:
27
4
        mpd_queue._add(MPD_COMMAND::PREV);
28
4
        break;
29
40
    default:
30
12
        log_file_mutex.mutex_lock();
31
12
        log_file_cout << CRITICAL << "nieznana komenda MPD z pilota "<< std::endl;
32
12
        log_file_mutex.mutex_unlock();
33
12
        break;
34
40
    }
35
40
}
36
37
void c_irda_logic::sleeperLogic(PILOT_KEY X)
38
40
{
39
40
    my_data->mainLCD->set_print_song_state(100);
40
40
    my_data->mainLCD->printString(true,0,0,std::to_string(my_data->sleeper)+" minut");
41
40
42
40
    switch (X){
43
40
    case PILOT_KEY::KEY_EXIT:
44
4
    {
45
4
        my_data->sleeper=0;
46
4
        my_data->mainLCD->set_print_song_state(0);
47
4
        who = PILOT_STATE::MPD;
48
4
        break;
49
40
    }
50
40
    case PILOT_KEY::KEY_UP:
51
16
    {
52
16
        ++my_data->sleeper;
53
16
        my_data->mainLCD->printString(true,0,0,std::to_string(my_data->sleeper)+" minut");
54
16
        break;
55
40
    }
56
40
    case PILOT_KEY::KEY_DOWN:
57
4
    {
58
4
        --my_data->sleeper;
59
4
        my_data->mainLCD->printString(true,0,0,std::to_string(my_data->sleeper)+" minut");
60
4
        break;
61
40
    }
62
40
    case PILOT_KEY::KEY_CHANNELUP:
63
4
    {
64
4
        my_data->sleeper+=10;
65
4
        my_data->mainLCD->printString(true,0,0,std::to_string(my_data->sleeper)+" minut");
66
4
        break;
67
40
    }
68
40
    case PILOT_KEY::KEY_CHANNELDOWN:
69
4
    {
70
4
        my_data->sleeper-=10;
71
4
        my_data->mainLCD->printString(true,0,0,std::to_string(my_data->sleeper)+" minut");
72
4
        break;
73
40
    }
74
40
    case PILOT_KEY::KEY_OK:
75
4
    {
76
4
        iDOM_THREAD::start_thread("Sleeper MPD",useful_F::sleeper_mpd,my_data);
77
4
        my_data->mainLCD->printString(true,1,0,"SLEEPer START");
78
4
        my_data->mainLCD->set_print_song_state(0);
79
4
        who = PILOT_STATE::MPD;
80
4
        break;
81
40
    }
82
40
    default:
83
4
        log_file_mutex.mutex_lock();
84
4
        log_file_cout << CRITICAL << "nieznany case w sleeperLogic"<< std::endl;
85
4
        log_file_mutex.mutex_unlock();
86
4
        break;
87
40
    }
88
40
}
89
90
void c_irda_logic::projectorLogic(PILOT_KEY X)
91
48
{
92
48
    my_data->mainLCD->set_print_song_state(100);
93
48
    my_data->mainLCD->printString(false,2,1,"  PROJEKTOR   ");
94
48
95
48
    switch (X)
96
48
    {
97
48
    case PILOT_KEY::KEY_EXIT:
98
8
    {
99
8
        my_data->mainLCD->set_print_song_state(0);
100
8
        who = PILOT_STATE::MPD;
101
8
102
8
        if(my_data->ptr_MPD_info->isPlay == true){
103
4
            iDomTOOLS::MPD_play(my_data);
104
4
        }
105
4
        else {
106
4
            iDomTOOLS::turnOffSpeakers();
107
4
            my_data->mainLCD->set_print_song_state(0); // off display
108
4
            my_data->mainLCD->set_lcd_STATE(0);
109
4
        }
110
8
        break;
111
48
    }
112
48
    case PILOT_KEY::DUMMY:
113
4
    {
114
4
        break;
115
48
    }
116
48
    case PILOT_KEY::KEY_VOLUMEUP:
117
4
    {
118
4
        useful_F_libs::write_to_mkfifo(my_data->server_settings->omxplayerFile, "+");
119
4
        break;
120
48
    }
121
48
    case PILOT_KEY::KEY_VOLUMEDOWN:
122
4
    {
123
4
        useful_F_libs::write_to_mkfifo(my_data->server_settings->omxplayerFile, "-");
124
4
        break;
125
48
    }
126
48
    case PILOT_KEY::KEY_OK:
127
4
    {
128
4
        my_data->mainLCD->set_print_song_state(1000);
129
4
        my_data->mainLCD->printString(false,0,0,"ODTWARZAM VIDEO");
130
4
        useful_F_libs::write_to_mkfifo(my_data->server_settings->omxplayerFile, "p");
131
4
        break;
132
48
    }
133
48
    case PILOT_KEY::KEY_POWER:
134
4
    {
135
4
        //system("echo -n q > /mnt/ramdisk/cmd &"); // zamykanie omxplayera
136
4
        useful_F_libs::write_to_mkfifo(my_data->server_settings->omxplayerFile, "q");
137
4
        break;
138
48
    }
139
48
    case PILOT_KEY::KEY_DOWN:
140
4
    {
141
4
        useful_F::runLinuxCommand("echo -n $'\x1b\x5b\x43' > /mnt/ramdisk/cmd"); // do przodu
142
4
        //write_to_mkfifo("$'\x1b\x5b\x43'");
143
4
        break;
144
48
    }
145
48
    case PILOT_KEY::KEY_UP:
146
4
    {
147
4
        useful_F::runLinuxCommand("echo -n $'\x1b\x5b\x44' > /mnt/ramdisk/cmd"); // do tylu
148
4
        // write_to_mkfifo("$'\x1b\x5b\x44'");
149
4
        break;
150
48
    }
151
48
    case PILOT_KEY::KEY_CHANNELUP:
152
4
    {
153
4
        //system("echo -n o > /mnt/ramdisk/cmd"); // do przodu
154
4
        useful_F_libs::write_to_mkfifo(my_data->server_settings->omxplayerFile, "o");
155
4
        break;
156
48
    }
157
48
    case PILOT_KEY::KEY_CHANNELDOWN:
158
4
    {
159
4
        //system("echo -n i > /mnt/ramdisk/cmd"); // do tylu
160
4
        useful_F_libs::write_to_mkfifo(my_data->server_settings->omxplayerFile, "i");
161
4
        break;
162
48
    }
163
48
    default:
164
4
        log_file_mutex.mutex_lock();
165
4
        log_file_cout << CRITICAL << "nieznany case w projector"<< std::endl;
166
4
        log_file_mutex.mutex_unlock();
167
4
        break;
168
48
    }
169
48
}
170
171
void c_irda_logic::movieLogic(PILOT_KEY X)
172
56
{
173
56
    switch (X)
174
56
    {
175
56
    case PILOT_KEY::KEY_EXIT:
176
4
    {
177
4
        my_data->mainLCD->set_print_song_state(0);
178
4
        my_data->mainLCD->set_lcd_STATE(2);
179
4
        who = PILOT_STATE::MPD; // koniec przegladania katalogow
180
4
        break;
181
56
    }
182
56
    case PILOT_KEY::KEY_VOLUMEUP:
183
12
    {
184
12
        my_data->main_tree->next(); // naspteny katalog
185
12
        break;
186
56
    }
187
56
    case PILOT_KEY::KEY_VOLUMEDOWN:
188
20
    {
189
20
        my_data->main_tree->previous(); //poprzedni katalog
190
20
        break;
191
56
    }
192
56
    case PILOT_KEY::KEY_OK:
193
12
    {
194
12
        // whodze w katalog lub odtwarzma plik
195
12
196
12
        if (my_data->main_tree->is_file() == false)
197
4
        {
198
4
            my_data->main_tree->enter_dir();
199
4
            my_data->main_tree->show_list();
200
4
        }
201
8
        else
202
8
        {
203
8
            std::cout << " URUCHAMIAM PLIK! " <<my_data->main_tree->show_list() <<std::endl;
204
8
205
8
            std::string command = "/home/pi/programowanie/iDom_server_OOP/script/PYTHON/iDom_movie.py ";
206
8
            command+=my_data->main_tree->show_list();
207
8
            useful_F::runLinuxCommand(command);
208
8
            std::cout << " WYSTARTOWALEM!!";
209
8
            my_data->mainLCD->set_lcd_STATE(-1);
210
8
            my_data->mainLCD->printString(true,0,0,"odtwarzam film");
211
8
            my_data->mainLCD->printString(false,0,1,my_data->main_tree->show_list());
212
8
            who = PILOT_STATE::PROJECTOR;
213
8
214
8
            log_file_mutex.mutex_lock();
215
8
            log_file_cout << INFO << "odtwarzam film "<< my_data->ptr_MPD_info->isPlay << std::endl;
216
8
            log_file_mutex.mutex_unlock();
217
8
218
8
            if (my_data->ptr_MPD_info->isPlay == true){
219
4
                iDomTOOLS::MPD_pause(); // projektor wlaczony wiec pauzuje radio
220
4
            }
221
4
            else{
222
4
                iDomTOOLS::turnOnSpeakers();
223
4
                puts("wlaczam glosnik do filmu");
224
4
            }
225
8
        }
226
12
        break;
227
56
    }
228
56
    case PILOT_KEY::KEY_UP:
229
4
    {
230
4
        my_data->main_tree->back_dir();
231
4
        break;
232
56
    }
233
56
    default:
234
4
        log_file_mutex.mutex_lock();
235
4
        log_file_cout << CRITICAL << "nieznany case w moveLogic"<< std::endl;
236
4
        log_file_mutex.mutex_unlock();
237
4
        break;
238
56
    }
239
56
240
56
    my_data->main_tree->show_list();
241
56
}
242
243
void c_irda_logic::menuLogic(PILOT_KEY X)
244
156
{
245
156
    switch (X)
246
156
    {
247
156
    case PILOT_KEY::KEY_EXIT:
248
4
    {
249
4
        my_data->mainLCD->set_print_song_state(0);
250
4
        my_data->mainLCD->set_lcd_STATE(2);
251
4
        who = PILOT_STATE::MPD; // koniec przegladania katalogow
252
4
        break;
253
156
    }
254
156
    case PILOT_KEY::KEY_VOLUMEUP:
255
92
    {
256
92
        my_data->main_MENU->next(); // naspteny katalog
257
92
        break;
258
156
    }
259
156
    case PILOT_KEY::KEY_VOLUMEDOWN:
260
24
    {
261
24
        my_data->main_MENU->previous(); //poprzedni katalog
262
24
        break;
263
156
    }
264
156
    case PILOT_KEY::KEY_OK:
265
28
    {
266
28
        // whodze w katalog lub odtwarzma plik
267
28
268
28
        if (my_data->main_MENU->is_file() == false)
269
4
        {
270
4
            my_data->main_MENU->enter_dir();
271
4
            my_data->main_MENU->show_list();
272
4
        }
273
24
        else
274
24
        {
275
24
            // menu start
276
24
            if (my_data->main_MENU->show_list() == "5.SLEEPer"){
277
8
                std::cout << " POBUDKA!!!!" << std::endl;
278
8
                who=PILOT_STATE::SLEEPER;
279
8
            }
280
16
            else if (my_data->main_MENU->show_list() == "2.TEMPERATURA"){
281
4
                std::cout << " temperatura !!!!" << std::endl;
282
4
                who=PILOT_STATE::MPD;
283
4
                _add(PILOT_KEY::KEY_SAT);
284
4
            }
285
12
            else if (my_data->main_MENU->show_list() == "4.PLIKI"){
286
12
                std::cout << " do filmow" << std::endl;
287
12
                who=PILOT_STATE::MPD;
288
12
                _add(PILOT_KEY::KEY_EPG);
289
12
                _add(PILOT_KEY::KEY_VOLUMEUP);
290
12
            }
291
24
        }
292
28
        break;
293
156
    }
294
156
    case PILOT_KEY::KEY_UP:
295
4
    {
296
4
        my_data->main_MENU->back_dir();
297
4
        break;
298
156
    }
299
156
    default:
300
4
        log_file_mutex.mutex_lock();
301
4
        log_file_cout << CRITICAL << "nieznany case w menuLogic"<< std::endl;
302
4
        log_file_mutex.mutex_unlock();
303
4
        break;
304
156
305
156
    }
306
156
    my_data->main_MENU->show_list();
307
156
}
308
309
void c_irda_logic::mainPilotHandler(PILOT_KEY X)
310
144
{
311
144
    switch (X){
312
144
313
144
    case PILOT_KEY::KEY_RADIO:
314
4
    {
315
4
        who = PILOT_STATE::PROJECTOR;
316
4
        _add(PILOT_KEY::DUMMY);
317
4
        break;
318
144
    }
319
144
320
144
    case PILOT_KEY::KEY_SUBTITLE:
321
4
    {
322
4
        my_data->mainLCD->set_lcd_STATE(10);
323
4
        my_data->mainLCD->printString(true,0,0,"GASZE LEDy");
324
4
        std::string temp_str="";
325
4
        temp_str.erase();
326
4
        temp_str += my_data->main_iDomTools->ledOFF();
327
4
        my_data->mainLCD->printString(false,0,1,temp_str);
328
4
        who=PILOT_STATE::MPD;
329
4
        break;
330
144
    }
331
144
332
144
    case PILOT_KEY::KEY_LANGUAGE:
333
36
    {
334
36
        my_data->mainLCD->set_lcd_STATE(10);
335
36
        my_data->mainLCD->printString(true,0,0,"ZAPALAM LEDy");
336
36
        std::string temp_str = my_data->ptr_pilot_led->colorLED[my_data->ptr_pilot_led->counter].getColorName();
337
36
        my_data->main_iDomTools->ledOn(my_data->ptr_pilot_led->colorLED[my_data->ptr_pilot_led->counter]);
338
36
339
36
        if (++my_data->ptr_pilot_led->counter > my_data->ptr_pilot_led->colorLED.size()-1 )
340
4
        {
341
4
            my_data->ptr_pilot_led->counter=0;
342
4
        }
343
36
344
36
        my_data->mainLCD->printString(false,0,1,temp_str);
345
36
        who = PILOT_STATE::MPD;
346
36
        break;
347
144
    }
348
144
349
144
    case PILOT_KEY::KEY_SAT:
350
4
    {
351
4
        my_data->mainLCD->set_lcd_STATE(10);
352
4
        my_data->mainLCD->printString(true,0,0,"SMOG: "+my_data->main_iDomTools->getSmog()+" mg/m^3");
353
4
        std::string temp_str = "I:";
354
4
        std::vector<std::string> temper = my_data->main_iDomTools->getTemperature();
355
4
        //temp_str += my_data_logic->main_iDomTools->getTemperatureString();// send_to_arduino(my_data_logic,"temperature:2;");
356
4
        temp_str += temper.at(0);
357
4
        temp_str += " O:"+ temper.at(1);
358
4
        my_data->mainLCD->printString(false,0,1,temp_str+" c");
359
4
        who = PILOT_STATE::MPD;
360
4
        break;
361
144
    }
362
144
363
144
    case PILOT_KEY::KEY_EPG:
364
12
        who = PILOT_STATE::MOVIE;
365
12
        my_data->main_tree->show_list(); //printuje pierwszy element
366
12
        my_data->mainLCD->set_print_song_state(100);
367
12
        break;
368
144
369
144
    case PILOT_KEY::KEY_MENU:
370
28
        who = PILOT_STATE::MENU;
371
28
        my_data->main_MENU->show_list();
372
28
        my_data->mainLCD->set_print_song_state(100);
373
28
        break;
374
144
    case PILOT_KEY::KEY_FAVORITES:
375
4
        my_data->main_iDomTools->turnOnOffPrinter();
376
4
        break;
377
144
    case PILOT_KEY::KEY_TEXT:
378
8
        my_data->main_iDomTools->turnOnOff433MHzSwitch("listwa");
379
8
        break;
380
144
    case PILOT_KEY::KEY_REFRESH:
381
4
        my_data->main_iDomTools->startKodi_Thread();
382
4
        break;
383
144
    default:
384
40
        irdaMPD(X);
385
144
    }
386
144
}
387
388
c_irda_logic::c_irda_logic(thread_data *my_data):my_data(my_data)
389
48
{
390
48
    // my_data = my_data;
391
48
    who = PILOT_STATE::MPD;
392
48
}
393
394
void c_irda_logic::_add(PILOT_KEY X)
395
444
{
396
444
    switch (who){
397
444
    case PILOT_STATE::MPD:
398
140
        mainPilotHandler(X);
399
140
        break;
400
444
    case PILOT_STATE::SLEEPER:
401
40
        sleeperLogic(X);
402
40
        break;
403
444
    case PILOT_STATE::PROJECTOR:
404
48
        projectorLogic(X);
405
48
        break;
406
444
    case PILOT_STATE::MOVIE:
407
56
        movieLogic(X);
408
56
        break;
409
444
    case PILOT_STATE::MENU:
410
156
        menuLogic(X);
411
156
        break;
412
444
    default:
413
4
        log_file_mutex.mutex_lock();
414
4
        log_file_cout << CRITICAL << "nieznany pilotState"<< std::endl;
415
4
        log_file_mutex.mutex_unlock();
416
4
        break;
417
444
    }
418
444
}
419
420
//PILOT_KEY c_irda_logic::_get( )
421
//{
422
//    PILOT_KEY temp = PILOT_KEY::DUMMY;
423
//    if (irda_queue.empty() == false){
424
//        temp = irda_queue.front();
425
//        irda_queue.pop();
426
//    }
427
//    return temp;
428
//}
429
430
//int c_irda_logic::_size() const
431
//{
432
//    return irda_queue.size();
433
//}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/c_irda_logic/test/c_irda_logic_BT.cpp
Line
Count
Source (jump to first uncovered line)
1
#include <gtest/gtest.h>
2
#include "../../iDom_server_OOP.h"
3
#include "test_data.h"
4
#include "../../../iDom_server_OOP/src/iDomTools/test/iDomTools_fixture.h"
5
#include "../c_irda_logic.h"
6
7
8
class c_irda_logic_fixture : public iDomTOOLS_ClassTest
9
{
10
public:
11
    std::unique_ptr<c_irda_logic> test_irda;
12
    menu_tree* test_menuTree;
13
    files_tree* test_filesTree;
14
    std::string test_omxplayerFile = "../config/cmd_test";
15
    void SetUp()
16
48
    {
17
48
        iDomTOOLS_ClassTest::SetUp();
18
48
        test_irda = std::make_unique<c_irda_logic>(&test_my_data);
19
48
        test_menuTree = new menu_tree("../config/MENU/", test_my_data.mainLCD);
20
48
        test_my_data.main_MENU = test_menuTree;
21
48
22
48
        test_filesTree = new files_tree("../config/MOVIE/", test_my_data.mainLCD);
23
48
        test_my_data.main_tree = test_filesTree;
24
48
25
48
        test_my_data.server_settings->omxplayerFile =  test_omxplayerFile;
26
48
27
48
        std::cout << "c_irda_logic_fixture SetUp()"<<std::endl;
28
48
    }
29
30
    void TearDown()
31
48
    {
32
48
        delete test_menuTree;
33
48
        delete test_filesTree;
34
48
        iDomTOOLS_ClassTest::TearDown();
35
48
        std::cout << "c_irda_logic_fixture TearDown()"<<std::endl;
36
48
    }
37
};
38
39
TEST_F(c_irda_logic_fixture, kodi)
40
4
{
41
4
    std::array<Thread_array_struc,iDomConst::MAX_CONNECTION >test_ThreadArrayStruc;
42
4
43
44
    for (int i = 0 ; i < iDomConst::MAX_CONNECTION; i++)
44
40
        test_ThreadArrayStruc.at(i).thread_socket = i+1;
45
4
    test_ThreadArrayStruc.at(3).thread_socket = 0;
46
4
    test_my_data.main_THREAD_arr = &test_ThreadArrayStruc;
47
4
48
4
    test_my_data.main_iDomTools->unlockHome();
49
4
    test_my_data.main_iDomStatus->setObjectState("music",STATE::PAUSE);
50
4
    test_my_data.main_iDomStatus->setObjectState("speakers",STATE::OFF);
51
4
    test_irda->_add(PILOT_KEY::KEY_REFRESH);
52
4
    sleep(1);
53
4
}
54
55
TEST_F(c_irda_logic_fixture, turnOnOffListwa)
56
4
{
57
4
    test_my_data.main_iDomTools->unlockHome();
58
4
    test_my_data.main_iDomStatus->setObjectState("listwa",STATE::OFF);
59
4
60
4
    EXPECT_EQ(test_my_data.main_REC->getEqPointer("listwa")->getState(), STATE::UNDEFINE);
61
4
    test_irda->_add(PILOT_KEY::KEY_TEXT);
62
4
63
8
    EXPECT_EQ(test_my_data.main_REC->getEqPointer("listwa")->getState(),
64
8
              STATE::ON) << "wrong state: "
65
8
                         << stateToString(test_my_data.main_REC->getEqPointer("listwa")->getState());
66
4
    test_irda->_add(PILOT_KEY::KEY_TEXT);
67
4
68
8
    EXPECT_EQ(test_my_data.main_REC->getEqPointer("listwa")->getState(),
69
8
              STATE::OFF) << "wrong state: "
70
8
                          << stateToString(test_my_data.main_REC->getEqPointer("listwa")->getState());
71
4
}
72
73
TEST_F(c_irda_logic_fixture, turnOnOffPrinter)
74
4
{
75
4
    setReturnPinState(0);
76
4
    test_my_data.main_iDomTools->unlockHome();
77
4
    test_my_data.main_iDomStatus->setObjectState("printer", STATE::OFF);
78
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("printer"),
79
4
              STATE::OFF);
80
4
81
4
    test_irda->mainPilotHandler(PILOT_KEY::KEY_FAVORITES);
82
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("printer"),
83
4
              STATE::ON);
84
4
    std::cout <<"event: " << test_my_data.myEventHandler.run("230V")->getEvent() <<std::endl;
85
4
}
86
87
TEST_F(c_irda_logic_fixture, irdaMPD)
88
4
{
89
4
    blockQueue test_Q;
90
4
    test_Q._clearAll();
91
4
92
4
    test_irda->_add(PILOT_KEY::KEY_POWER);
93
4
    EXPECT_EQ(test_Q._get(), MPD_COMMAND::STOP);
94
4
95
4
    test_irda->_add(PILOT_KEY::KEY_TV);
96
4
    EXPECT_EQ(test_Q._get(), MPD_COMMAND::PLAY);
97
4
98
4
    test_irda->_add(PILOT_KEY::KEY_VOLUMEDOWN);
99
4
    EXPECT_EQ(test_Q._get(), MPD_COMMAND::VOLDOWN);
100
4
101
4
    test_irda->_add(PILOT_KEY::KEY_VOLUMEUP);
102
4
    EXPECT_EQ(test_Q._get(), MPD_COMMAND::VOLUP);
103
4
104
4
    test_irda->_add(PILOT_KEY::KEY_AUDIO);
105
4
    EXPECT_EQ(test_Q._get(), MPD_COMMAND::PAUSE);
106
4
107
4
    test_irda->_add(PILOT_KEY::KEY_UP);
108
4
    EXPECT_EQ(test_Q._get(), MPD_COMMAND::NEXT);
109
4
110
4
    test_irda->_add(PILOT_KEY::KEY_DOWN);
111
4
    EXPECT_EQ(test_Q._get(), MPD_COMMAND::PREV);
112
4
113
4
    test_irda->_add(PILOT_KEY::KEY_2); //default
114
4
    EXPECT_EQ(test_Q._size(), 0);
115
4
}
116
TEST_F(c_irda_logic_fixture, sleeper_Logic_EXIT)
117
4
{
118
4
    test_my_data.sleeper = 0;
119
4
    EXPECT_EQ(test_my_data.sleeper, 0);
120
4
    test_irda->_add(PILOT_KEY::KEY_MENU);
121
16
    do {
122
16
        test_irda->_add(PILOT_KEY::KEY_VOLUMEUP);
123
16
    } while(TEST_DATA::LCD_print != "5.SLEEPer");
124
20
    do {
125
20
        test_irda->_add(PILOT_KEY::KEY_VOLUMEDOWN);
126
20
    } while(TEST_DATA::LCD_print != "5.SLEEPer");
127
4
    test_irda->_add(PILOT_KEY::KEY_OK);
128
4
    test_irda->_add(PILOT_KEY::KEY_UP);
129
4
    EXPECT_EQ(test_my_data.sleeper, 1);
130
4
    test_irda->_add(PILOT_KEY::KEY_UP);
131
4
    EXPECT_EQ(test_my_data.sleeper, 2);
132
4
    test_irda->_add(PILOT_KEY::KEY_EXIT);
133
4
    EXPECT_EQ(test_my_data.sleeper, 0);
134
4
}
135
136
TEST_F(c_irda_logic_fixture, sleeper_Logic_OK)
137
4
{
138
4
    std::cout << test_my_data.main_REC->listAllName() << std::endl;
139
4
140
4
    std::array<Thread_array_struc,iDomConst::MAX_CONNECTION> test_ThreadArrayStruc;
141
4
142
44
    for (int i = 0 ; i < iDomConst::MAX_CONNECTION; i++)
143
40
        test_ThreadArrayStruc.at(i).thread_socket = i+1;
144
4
    test_ThreadArrayStruc.at(3).thread_socket = 0;
145
4
    test_my_data.main_THREAD_arr = &test_ThreadArrayStruc;
146
4
    test_my_data.sleeper = 0;
147
4
    EXPECT_EQ(test_my_data.sleeper, 0);
148
4
    test_irda->_add(PILOT_KEY::KEY_MENU);
149
16
    do {
150
16
        test_irda->_add(PILOT_KEY::KEY_VOLUMEUP);
151
16
    } while(TEST_DATA::LCD_print != "5.SLEEPer");
152
4
    test_irda->_add(PILOT_KEY::KEY_OK);
153
4
    test_irda->_add(PILOT_KEY::KEY_UP);
154
4
    EXPECT_EQ(test_my_data.sleeper, 1);
155
4
    test_irda->_add(PILOT_KEY::KEY_UP);
156
4
    EXPECT_EQ(test_my_data.sleeper, 2);
157
4
    test_irda->_add(PILOT_KEY::KEY_CHANNELUP);
158
4
    EXPECT_EQ(test_my_data.sleeper, 12);
159
4
    test_irda->_add(PILOT_KEY::KEY_CHANNELDOWN);
160
4
    EXPECT_EQ(test_my_data.sleeper, 2);
161
4
    test_irda->_add(PILOT_KEY::KEY_DOWN);
162
4
    EXPECT_EQ(test_my_data.sleeper, 1);
163
4
    test_irda->_add(PILOT_KEY::KEY_OK);
164
4
    sleep(2);
165
4
    EXPECT_EQ(test_my_data.sleeper, 0);
166
4
    test_irda->_add(PILOT_KEY::KEY_EXIT);
167
4
    EXPECT_EQ(test_my_data.sleeper, 0);\
168
4
169
4
    //////////////default
170
4
    test_irda->who = PILOT_STATE::SLEEPER;
171
4
    test_irda->_add(PILOT_KEY::KEY_0); //default
172
4
}
173
174
TEST_F(c_irda_logic_fixture, LED_ON_OFF)
175
4
{
176
4
    EXPECT_EQ( test_my_data.myEventHandler.run("LED")->getLast1minNumberEvent(),0);
177
40
    for (int i = 1 ; i < test_my_data.ptr_pilot_led->colorLED.size()+2; ++i)
178
36
    {
179
36
        test_irda->_add(PILOT_KEY::KEY_LANGUAGE);
180
36
        EXPECT_EQ( test_my_data.myEventHandler.run("LED")->getLast1minNumberEvent(),i);
181
36
        EXPECT_THAT(test_my_data.myEventHandler.run("LED")->getEvent(),
182
36
                    testing::HasSubstr("LED can not start due to home state: UNDEFINE"));
183
36
    }
184
4
    test_irda->_add(PILOT_KEY::KEY_SUBTITLE);
185
4
}
186
TEST_F(c_irda_logic_fixture, temp_smogINFO)
187
4
{
188
4
    TEST_DATA::return_httpPost = "ok.\n";
189
4
    TEST_DATA::return_send_to_arduino = "12:12";
190
4
    test_irda->_add(PILOT_KEY::KEY_MENU);
191
4
    do {
192
4
        test_irda->_add(PILOT_KEY::KEY_VOLUMEUP);
193
4
    } while(TEST_DATA::LCD_print != "2.TEMPERATURA");
194
4
195
4
    test_irda->_add(PILOT_KEY::KEY_VOLUMEUP);
196
4
    test_irda->_add(PILOT_KEY::KEY_VOLUMEDOWN);
197
4
    test_irda->_add(PILOT_KEY::KEY_OK);
198
4
    EXPECT_THAT(TEST_DATA::LCD_print, testing::HasSubstr("TEMPERATURA"));
199
4
}
200
201
TEST_F(c_irda_logic_fixture, menu_enter_dir)
202
4
{
203
4
    test_irda->_add(PILOT_KEY::KEY_MENU);
204
4
    test_irda->_add(PILOT_KEY::KEY_OK);
205
4
206
4
    EXPECT_EQ(test_irda->who, PILOT_STATE::MENU);
207
4
    test_irda->_add(PILOT_KEY::KEY_UP);
208
4
    test_irda->_add(PILOT_KEY::KEY_0); //default
209
4
    test_irda->_add(PILOT_KEY::KEY_EXIT);
210
4
    EXPECT_EQ(test_irda->who, PILOT_STATE::MPD);
211
4
}
212
TEST_F(c_irda_logic_fixture, menu_files)
213
4
{
214
4
    blockQueue  test_q;
215
4
    test_q._clearAll();
216
4
    test_my_data.idom_all_state.houseState = STATE::UNLOCK;
217
4
    int timeout = 10;
218
4
    test_irda->_add(PILOT_KEY::KEY_MENU);
219
12
    do {
220
12
        if (--timeout == 0)
221
12
            FAIL()<<"cannot find";
222
12
        test_irda->_add(PILOT_KEY::KEY_VOLUMEUP);
223
12
    } while(TEST_DATA::LCD_print != "4.PLIKI");
224
4
    test_irda->_add(PILOT_KEY::KEY_OK);
225
4
    EXPECT_EQ(test_irda->who, PILOT_STATE::MOVIE);
226
4
    timeout = 10;
227
8
    do {
228
8
        if (--timeout == 0)
229
8
            FAIL()<<"cannot find";
230
8
        test_irda->_add(PILOT_KEY::KEY_VOLUMEDOWN);
231
8
    } while(TEST_DATA::LCD_print != "GAME_OF_THRONES/");
232
4
    test_irda->_add(PILOT_KEY::KEY_OK);
233
4
    test_irda->_add(PILOT_KEY::KEY_UP);
234
4
    EXPECT_STREQ(TEST_DATA::LCD_print.c_str(),"GAME_OF_THRONES/");
235
4
    test_irda->_add(PILOT_KEY::KEY_EXIT);
236
4
    EXPECT_EQ(test_irda->who, PILOT_STATE::MPD);
237
4
    ///////////////// play - no MPD
238
4
239
4
    test_my_data.ptr_MPD_info->isPlay  = false;
240
4
    test_irda->_add(PILOT_KEY::KEY_MENU);
241
4
    timeout = 10;
242
20
    do {
243
20
        if (--timeout == 0)
244
20
            FAIL()<<"cannot find";
245
20
        test_irda->_add(PILOT_KEY::KEY_VOLUMEUP);
246
20
    } while(TEST_DATA::LCD_print != "4.PLIKI");
247
4
    test_irda->_add(PILOT_KEY::KEY_OK);
248
4
    EXPECT_EQ(test_irda->who, PILOT_STATE::MOVIE);
249
4
    timeout = 10;
250
8
    do {
251
8
        if (--timeout == 0)
252
0
            break;
253
8
        test_irda->_add(PILOT_KEY::KEY_VOLUMEDOWN);
254
8
    } while(TEST_DATA::LCD_print != "s01e02");
255
4
    test_irda->_add(PILOT_KEY::KEY_0); //default
256
4
    test_irda->_add(PILOT_KEY::KEY_OK);
257
4
    EXPECT_EQ(test_irda->who, PILOT_STATE::PROJECTOR);
258
4
    test_irda->_add(PILOT_KEY::KEY_EXIT);
259
4
    EXPECT_EQ(test_irda->who, PILOT_STATE::MPD);
260
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("speakers"),STATE::OFF);
261
4
    ///////////////// play -  MPD
262
4
    test_my_data.ptr_MPD_info->isPlay  = true;
263
4
    EXPECT_TRUE(test_my_data.ptr_MPD_info->isPlay);
264
4
    test_irda->_add(PILOT_KEY::KEY_MENU);
265
4
    timeout = 10;
266
20
    do {
267
20
        if (--timeout == 0)
268
20
            FAIL()<<"cannot find";
269
20
        test_irda->_add(PILOT_KEY::KEY_VOLUMEUP);
270
20
    } while(TEST_DATA::LCD_print != "4.PLIKI");
271
4
    test_irda->_add(PILOT_KEY::KEY_OK);
272
4
    EXPECT_EQ(test_irda->who, PILOT_STATE::MOVIE);
273
4
    timeout = 10;
274
4
    do {
275
4
        if (--timeout == 0)
276
4
            FAIL()<<"cannot find";
277
4
        test_irda->_add(PILOT_KEY::KEY_VOLUMEDOWN);
278
4
    } while(TEST_DATA::LCD_print != "s01e02");
279
4
    test_irda->_add(PILOT_KEY::KEY_OK);
280
4
    EXPECT_EQ(test_irda->who, PILOT_STATE::PROJECTOR);
281
4
282
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PAUSE);
283
4
}
284
285
TEST_F(c_irda_logic_fixture, dummy_KEY_RADIO_and_add )
286
4
{
287
4
    test_irda->_add(PILOT_KEY::KEY_RADIO);
288
4
    EXPECT_EQ(test_irda->who, PILOT_STATE::PROJECTOR);
289
4
290
4
    test_irda->who = PILOT_STATE::LED; //not set
291
4
    test_irda->_add(PILOT_KEY::KEY_RADIO);
292
4
}
293
294
TEST_F(c_irda_logic_fixture, projektor)
295
4
{
296
4
    std::string retString;
297
4
    test_irda->who = PILOT_STATE::PROJECTOR;
298
4
    test_irda->_add(PILOT_KEY::KEY_VOLUMEUP);
299
4
    retString = useful_F_libs::read_from_mkfifo(test_omxplayerFile.c_str());
300
4
    std::cout << "DUPA: " << retString.size() << std::endl;
301
4
   // EXPECT_EQ(retString,"+");
302
4
303
4
    test_irda->_add(PILOT_KEY::KEY_VOLUMEDOWN);
304
4
    retString = useful_F_libs::read_from_mkfifo(test_omxplayerFile.c_str());
305
4
    std::cout << "DUPA: " << retString.size() << std::endl;
306
4
   // EXPECT_EQ(retString,"+");
307
4
308
4
    test_irda->_add(PILOT_KEY::KEY_OK);
309
4
    retString = useful_F_libs::read_from_mkfifo(test_omxplayerFile.c_str());
310
4
    std::cout << "DUPA: " << retString.size() << std::endl;
311
4
   // EXPECT_EQ(retString,"-");
312
4
313
4
    test_irda->_add(PILOT_KEY::KEY_POWER);
314
4
    retString = useful_F_libs::read_from_mkfifo(test_omxplayerFile.c_str());
315
4
    std::cout << "DUPA: " << retString.size() << std::endl;
316
4
   // EXPECT_EQ(retString,"q");
317
4
318
4
    test_irda->_add(PILOT_KEY::KEY_DOWN);
319
4
    retString = useful_F_libs::read_from_mkfifo(test_omxplayerFile.c_str());
320
4
    std::cout << "DUPA: " << retString.size() << std::endl;
321
4
   // EXPECT_EQ(retString,"+");
322
4
323
4
    test_irda->_add(PILOT_KEY::KEY_UP);
324
4
    retString = useful_F_libs::read_from_mkfifo(test_omxplayerFile.c_str());
325
4
    std::cout << "DUPA: " << retString.size() << std::endl;
326
4
   // EXPECT_EQ(retString,"+");
327
4
328
4
    test_irda->_add(PILOT_KEY::KEY_CHANNELUP);
329
4
    retString = useful_F_libs::read_from_mkfifo(test_omxplayerFile.c_str());
330
4
    std::cout << "DUPA: " << retString.size() << std::endl;
331
4
   // EXPECT_EQ(retString,"o");
332
4
333
4
    test_irda->_add(PILOT_KEY::KEY_CHANNELDOWN);
334
4
    retString = useful_F_libs::read_from_mkfifo(test_omxplayerFile.c_str());
335
4
    std::cout << "DUPA: " << retString.size() << std::endl;
336
4
   // EXPECT_EQ(retString,"i");
337
4
338
4
    test_my_data.ptr_MPD_info->isPlay = true;
339
4
    test_irda->_add(PILOT_KEY::KEY_EXIT);
340
4
    retString = useful_F_libs::read_from_mkfifo(test_omxplayerFile.c_str());
341
4
    std::cout << "DUPA: " << retString.size() << std::endl;
342
4
    EXPECT_EQ(test_irda->who, PILOT_STATE::MPD);
343
4
344
4
    test_my_data.ptr_MPD_info->isPlay = false;
345
4
    test_irda->_add(PILOT_KEY::KEY_EXIT);
346
4
    retString = useful_F_libs::read_from_mkfifo(test_omxplayerFile.c_str());
347
4
    std::cout << "DUPA: " << retString.size() << std::endl;
348
4
    EXPECT_EQ(test_irda->who, PILOT_STATE::MPD);
349
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("speakers"),STATE::OFF);
350
4
351
4
    //// dummy
352
4
    test_irda->who = PILOT_STATE::PROJECTOR;
353
4
    test_irda->_add(PILOT_KEY::KEY_0);
354
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/command.cpp
Line
Count
Source
1
#include "command.h"
2
3
command::command(const std::string &commandName ) : commandName(commandName)
4
1.07k
{
5
1.07k
   // std::cout << "konstruktor command"<<std::endl;
6
1.07k
}
7
8
command::~command()
9
1.07k
{
10
1.07k
  // puts("command::~command()");
11
1.07k
}
12
13
std::string command::getCommandName()
14
624
{
15
624
    return commandName;
16
624
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_433mhz_BT.cpp
Line
Count
Source
1
#include "../command_433mhz.h"
2
#include "../../../functions/functions.h"
3
#include "../../../RADIO_433_eq/radio_433_eq.h"
4
#include "../../../433MHz/RFLink/rflinkhandler.h"
5
#include "../../../iDomTools/test/iDomTools_fixture.h"
6
7
class command433MHz_Class_fixture : public iDomTOOLS_ClassTest
8
{
9
public:
10
    command433MHz_Class_fixture()
11
60
    {
12
60
        this->test_command_433MHz = std::nullptr_t();
13
60
        this->test_RFLink = std::nullptr_t();
14
60
    }
15
16
protected:
17
    std::vector<std::string> test_v= {"433MHz"};
18
    RFLinkHandler* test_RFLink;
19
    blockQueue test_q;
20
    command_433MHz* test_command_433MHz;
21
22
    void SetUp() final
23
60
    {
24
60
        iDomTOOLS_ClassTest::SetUp();
25
60
26
60
        test_q._clearAll();
27
60
28
60
        test_RFLink = new RFLinkHandler(&test_my_data);
29
60
        test_command_433MHz = new command_433MHz("433MHz");
30
60
        test_my_data.main_RFLink = test_RFLink;
31
60
        std::cout << "command433MHz_Class_fixture SetUp" << std::endl;
32
60
    }
33
34
    void TearDown() final
35
60
    {
36
60
        iDomTOOLS_ClassTest::TearDown();
37
60
        delete test_RFLink;
38
60
        delete test_command_433MHz;
39
60
        std::cout << "command433MHz_Class_fixture TearDown" << std::endl;
40
60
    }
41
42
    void addSwitch(const std::string& name)
43
4
    {
44
4
        test_v.clear();
45
4
        test_v.push_back("433MHz");
46
4
        test_v.push_back("add");
47
4
        test_v.push_back("SWITCH");
48
4
        test_v.push_back(name);
49
4
        test_v.push_back("1234");
50
4
        test_v.push_back("onCode_A");
51
4
        test_v.push_back("ofCode_A");
52
4
        test_v.push_back("on15sec_A");
53
4
        test_v.push_back("sunrise_A");
54
4
        test_v.push_back("sunset_A");
55
4
        test_v.push_back("lock_A");
56
4
        test_v.push_back("unlock_A");
57
4
        std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
58
4
    }
59
    void deleteSwitch(const std::string& name)
60
8
    {
61
8
        test_v.clear();
62
8
        test_v.push_back("433MHz");
63
8
        test_v.push_back("delete");
64
8
        test_v.push_back(name);
65
8
        std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
66
8
    }
67
};
68
TEST_F(command433MHz_Class_fixture, getCommandName)
69
4
{
70
4
    EXPECT_THAT(test_command_433MHz->getCommandName(),testing::HasSubstr("433MHz"));
71
4
}
72
73
TEST_F(command433MHz_Class_fixture, deleteSwitch)
74
4
{
75
4
    test_v.push_back("show");
76
4
    test_v.push_back("all");
77
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
78
4
    auto v = test_rec->getSwitchPointerVector();
79
4
    EXPECT_EQ(v.size(),5);
80
4
    test_v.clear();
81
4
    test_v.push_back("433MHz");
82
4
    test_v.push_back("delete");
83
4
    test_v.push_back("A");
84
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
85
4
    v = test_rec->getSwitchPointerVector();
86
4
    EXPECT_EQ(v.size(),4);
87
4
    test_v.clear();
88
4
    test_v.push_back("433MHz");
89
4
    test_v.push_back("show");
90
4
    test_v.push_back("all");
91
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
92
4
    addSwitch("A");
93
4
94
4
}
95
TEST_F(command433MHz_Class_fixture, deleteFakeSwitch)
96
4
{
97
4
    auto actualSize = test_rec->getSwitchPointerVector().size();
98
4
    test_v.push_back("show");
99
4
    test_v.push_back("all");
100
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
101
4
    auto v = test_rec->getSwitchPointerVector();
102
4
    EXPECT_EQ(v.size(),actualSize);
103
4
    test_v.clear();
104
4
    test_v.push_back("433MHz");
105
4
    test_v.push_back("delete");
106
4
    test_v.push_back("fake");
107
4
    std::string result = test_command_433MHz->execute(test_v,&test_my_data);
108
4
    EXPECT_THAT(result, testing::HasSubstr("not exist"));
109
4
    v = test_rec->getSwitchPointerVector();
110
4
    EXPECT_EQ(v.size(),actualSize);
111
4
    test_v.clear();
112
4
    test_v.push_back("433MHz");
113
4
    test_v.push_back("show");
114
4
    test_v.push_back("all");
115
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
116
4
}
117
TEST_F(command433MHz_Class_fixture, addButton)
118
4
{
119
4
    auto actualSize = test_rec->getButtonPointerVector().size();
120
4
    test_v.push_back("show");
121
4
    test_v.push_back("all");
122
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
123
4
    auto v = test_rec->getButtonPointerVector();
124
4
    EXPECT_EQ(v.size(),actualSize);
125
4
    test_v.clear();
126
4
    test_v.push_back("433MHz");
127
4
    test_v.push_back("add");
128
4
    test_v.push_back("BUTTON");
129
4
    test_v.push_back("glowny");
130
4
    test_v.push_back("4321");
131
4
    test_v.push_back("onCode");
132
4
    test_v.push_back("offCode");
133
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
134
4
    v = test_rec->getButtonPointerVector();
135
4
    EXPECT_EQ(v.size(),actualSize+1);
136
4
    test_v.clear();
137
4
    test_v.push_back("433MHz");
138
4
    test_v.push_back("show");
139
4
    test_v.push_back("all");
140
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
141
4
    deleteSwitch("glowny");
142
4
}
143
144
TEST_F(command433MHz_Class_fixture, addSwitch)
145
4
{
146
4
    auto actualSize = test_rec->getSwitchPointerVector().size();
147
4
    test_v.push_back("show");
148
4
    test_v.push_back("all");
149
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
150
4
    auto v = test_rec->getSwitchPointerVector();
151
4
    EXPECT_EQ(v.size(),actualSize);
152
4
    test_v.clear();
153
4
    test_v.push_back("433MHz");
154
4
    test_v.push_back("add");
155
4
    test_v.push_back("SWITCH");
156
4
    test_v.push_back("Aaa");
157
4
    test_v.push_back("1234");
158
4
    test_v.push_back("onCode_A");
159
4
    test_v.push_back("ofCode_A");
160
4
    test_v.push_back("on15sec_A");
161
4
    test_v.push_back("sunrise_A");
162
4
    test_v.push_back("sunset_A");
163
4
    test_v.push_back("lock_A");
164
4
    test_v.push_back("unlock_A");
165
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
166
4
    v = test_rec->getSwitchPointerVector();
167
4
    EXPECT_EQ(v.size(),actualSize+1);
168
4
    test_v.clear();
169
4
    test_v.push_back("433MHz");
170
4
    test_v.push_back("show");
171
4
    test_v.push_back("all");
172
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
173
4
    deleteSwitch("Aaa");
174
4
}
175
176
TEST_F(command433MHz_Class_fixture, addExistingWeather)
177
4
{
178
4
    test_v.push_back("show");
179
4
    test_v.push_back("all");
180
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
181
4
    auto v = test_rec->getWeather_StationPtrVector();
182
4
    EXPECT_EQ(v.size(),1);
183
4
    test_v.clear();
184
4
    test_v.push_back("433MHz");
185
4
    test_v.push_back("add");
186
4
    test_v.push_back("WEATHER");
187
4
    test_v.push_back("first");
188
4
    test_v.push_back("1234");
189
4
190
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
191
4
    v = test_rec->getWeather_StationPtrVector();
192
4
    EXPECT_EQ(v.size(),1);
193
4
    test_v.clear();
194
4
    test_v.push_back("433MHz");
195
4
    test_v.push_back("show");
196
4
    test_v.push_back("all");
197
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
198
4
}
199
200
TEST_F(command433MHz_Class_fixture, missingParamiter_addSwitch)
201
4
{
202
4
    test_v.push_back("show");
203
4
    test_v.push_back("all");
204
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
205
4
    auto v = test_rec->getSwitchPointerVector();
206
4
    EXPECT_EQ(v.size(),5);
207
4
    test_v.clear();
208
4
    test_v.push_back("433MHz");
209
4
    test_v.push_back("add");
210
4
    test_v.push_back("SWITCH");
211
4
    test_v.push_back("Abc");
212
4
    test_v.push_back("1234");
213
4
    test_v.push_back("onCode_A");
214
4
    test_v.push_back("ofCode_A");
215
4
    test_v.push_back("on15sec_A");
216
4
    std::string result = test_command_433MHz->execute(test_v,&test_my_data);
217
8
    EXPECT_THAT(result, testing::HasSubstr("mising paramiter")) << "nie ma bledu";
218
4
    v = test_rec->getSwitchPointerVector();
219
4
    EXPECT_EQ(v.size(),5);
220
4
    test_v.clear();
221
4
    test_v.push_back("433MHz");
222
4
    test_v.push_back("show");
223
4
    test_v.push_back("all");
224
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
225
4
}
226
\
227
TEST_F(command433MHz_Class_fixture, add_wrongType_addSwitch)
228
4
{
229
4
    test_v.push_back("show");
230
4
    test_v.push_back("all");
231
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
232
4
    auto v = test_rec->getSwitchPointerVector();
233
4
    EXPECT_EQ(v.size(),5);
234
4
    test_v.clear();
235
4
    test_v.push_back("433MHz");
236
4
    test_v.push_back("add");
237
4
    test_v.push_back("FAKE"); //here is wrong type
238
4
    test_v.push_back("Abc");
239
4
    test_v.push_back("1234");
240
4
    test_v.push_back("onCode_A");
241
4
    test_v.push_back("ofCode_A");
242
4
    test_v.push_back("on15sec_A");
243
4
    test_v.push_back("sunrise_A");
244
4
    test_v.push_back("sunset_A");
245
4
    test_v.push_back("lock_A");
246
4
    test_v.push_back("unlock_A");
247
4
    std::string result = test_command_433MHz->execute(test_v,&test_my_data);
248
4
    EXPECT_THAT(result, testing::HasSubstr("wrong type"));
249
4
    std::cout << "wynik testu: " << result << std::endl;
250
4
    v = test_rec->getSwitchPointerVector();
251
4
    EXPECT_EQ(v.size(),5);
252
4
    test_v.clear();
253
4
    test_v.push_back("433MHz");
254
4
    test_v.push_back("show");
255
4
    test_v.push_back("all");
256
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
257
4
}
258
259
TEST_F(command433MHz_Class_fixture, add_wrongID_addSwitch)
260
4
{
261
4
    test_v.push_back("show");
262
4
    test_v.push_back("all");
263
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
264
4
    auto v = test_rec->getSwitchPointerVector();
265
4
    EXPECT_EQ(v.size(),5);
266
4
    test_v.clear();
267
4
    test_v.push_back("433MHz");
268
4
    test_v.push_back("add");
269
4
    test_v.push_back("SWITCH");
270
4
    test_v.push_back("Abc");
271
4
    test_v.push_back("dummy"); //here is wrong ID
272
4
    test_v.push_back("onCode_A");
273
4
    test_v.push_back("ofCode_A");
274
4
    test_v.push_back("on15sec_A");
275
4
    test_v.push_back("sunrise_A");
276
4
    test_v.push_back("sunset_A");
277
4
    test_v.push_back("lock_A");
278
4
    test_v.push_back("unlock_A");
279
4
    std::string result = test_command_433MHz->execute(test_v,&test_my_data);
280
4
    std::cout << "wynik testu: " << result << std::endl;
281
4
    EXPECT_THAT(result, testing::HasSubstr("wrong ID"));
282
4
    v = test_rec->getSwitchPointerVector();
283
4
    EXPECT_EQ(v.size(),5);
284
4
    test_v.clear();
285
4
    test_v.push_back("433MHz");
286
4
    test_v.push_back("show");
287
4
    test_v.push_back("all");
288
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
289
4
}
290
291
TEST_F(command433MHz_Class_fixture, show_config)
292
4
{
293
4
    test_v.push_back("show");
294
4
    test_v.push_back("config");
295
4
    auto retStr = test_command_433MHz->execute(test_v,&test_my_data);
296
4
    EXPECT_GT(retStr.size(), 2210);
297
4
}
298
299
TEST_F(command433MHz_Class_fixture, show_switch)
300
4
{
301
4
    test_v.push_back("show");
302
4
    test_v.push_back("all");
303
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) << std::endl;
304
4
    auto v = test_rec->getSwitchPointerVector();
305
4
    EXPECT_EQ(v.size(),5);
306
4
    test_v.clear();
307
4
    test_v.push_back("433MHz");
308
4
    test_v.push_back("show");
309
4
    test_v.push_back("switch");
310
4
311
4
    std::string result = test_command_433MHz->execute(test_v,&test_my_data);
312
4
    std::cout << "wynik testu: " << result << std::endl;
313
4
    EXPECT_THAT(result, testing::HasSubstr("UNDEFINE"));
314
4
    v = test_rec->getSwitchPointerVector();
315
4
    EXPECT_EQ(v.size(),5);
316
4
    test_v.clear();
317
4
    test_v.push_back("433MHz");
318
4
    test_v.push_back("show");
319
4
    test_v.push_back("all");
320
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
321
4
}
322
323
TEST_F(command433MHz_Class_fixture, show_aether)
324
4
{
325
4
    test_my_data.main_RFLink->rflinkMAP["kk"].msg = "astro";
326
4
    test_my_data.main_RFLink->rflinkMAP["kk"].m_counter = 99;
327
4
    test_my_data.main_RFLink->rflinkMAP["jj"].msg = "lock";
328
4
    test_my_data.main_RFLink->rflinkMAP["jj"].m_counter = 155;
329
4
    test_v.push_back("show");
330
4
    test_v.push_back("all");
331
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
332
4
    auto v = test_rec->getSwitchPointerVector();
333
4
    EXPECT_EQ(v.size(),5);
334
4
    test_v.clear();
335
4
    test_v.push_back("433MHz");
336
4
    test_v.push_back("show");
337
4
    test_v.push_back("aether");
338
4
339
4
    std::string result = test_command_433MHz->execute(test_v,&test_my_data);
340
4
    std::cout << "wynik testu: " << result << std::endl;
341
4
    EXPECT_THAT(result, testing::HasSubstr("astro"));
342
4
    EXPECT_THAT(result, testing::HasSubstr("lock"));
343
4
    EXPECT_THAT(result, testing::HasSubstr("99"));
344
4
    EXPECT_THAT(result, testing::HasSubstr("155"));
345
4
    v = test_rec->getSwitchPointerVector();
346
4
    EXPECT_EQ(v.size(),5);
347
4
    test_v.clear();
348
4
}
349
350
TEST_F(command433MHz_Class_fixture, switchRF433)
351
4
{
352
4
    test_v.push_back("show");
353
4
    test_v.push_back("all");
354
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
355
4
    auto v = test_rec->getSwitchPointerVector();
356
4
    EXPECT_EQ(v.size(),5);
357
4
    /////////////////////////////// ON
358
4
    test_v.clear();
359
4
    test_v.push_back("433MHz");
360
4
    test_v.push_back("switch");
361
4
    test_v.push_back("B");
362
4
    test_v.push_back("ON");
363
4
    test_command_433MHz->execute(test_v,&test_my_data);
364
4
    EXPECT_EQ(test_my_data.main_REC->getEqPointer("B")->getState(), STATE::ON);
365
4
    ////////////////////////////// OFF
366
4
    test_v.clear();
367
4
    test_v.push_back("433MHz");
368
4
    test_v.push_back("switch");
369
4
    test_v.push_back("B");
370
4
    test_v.push_back("OFF");
371
4
    test_command_433MHz->execute(test_v,&test_my_data);
372
4
    EXPECT_EQ(test_my_data.main_REC->getEqPointer("B")->getState(), STATE::OFF);
373
4
    ////////////////////////////// 15s
374
4
    test_v.clear();
375
4
    test_v.push_back("433MHz");
376
4
    test_v.push_back("switch");
377
4
    test_v.push_back("B");
378
4
    test_v.push_back("15s");
379
4
    test_command_433MHz->execute(test_v,&test_my_data);
380
4
    EXPECT_EQ(test_my_data.main_REC->getEqPointer("B")->getState(), STATE::TEMPORARY);
381
4
    ////////////////////////////// unknown paramiter
382
4
    test_v.clear();
383
4
    test_v.push_back("433MHz");
384
4
    test_v.push_back("switch");
385
4
    test_v.push_back("B");
386
4
    test_v.push_back("fake");
387
4
    std::string result = test_command_433MHz->execute(test_v,&test_my_data);
388
4
    EXPECT_EQ(test_my_data.main_REC->getEqPointer("B")->getState(), STATE::TEMPORARY);
389
4
    EXPECT_THAT(result, testing::HasSubstr("fake"));
390
4
    ///////////////////////////// fake switch
391
4
    test_v.clear();
392
4
    test_v.push_back("433MHz");
393
4
    test_v.push_back("switch");
394
4
    test_v.push_back("B_fake");
395
4
    test_v.push_back("fake");
396
4
397
4
    result = test_command_433MHz->execute(test_v,&test_my_data);
398
4
    EXPECT_THAT(result, testing::HasSubstr("not found"));
399
4
    v = test_rec->getSwitchPointerVector();
400
4
    EXPECT_EQ(v.size(),5);
401
4
    test_v.clear();
402
4
}
403
404
405
TEST_F(command433MHz_Class_fixture, sendRF433)
406
4
{
407
4
    test_v.push_back("show");
408
4
    test_v.push_back("all");
409
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
410
4
    auto v = test_rec->getSwitchPointerVector();
411
4
    EXPECT_EQ(v.size(),5);
412
4
    test_v.clear();
413
4
    test_v.push_back("433MHz");
414
4
    test_v.push_back("send");
415
4
    test_v.push_back("fake");
416
4
417
4
    std::string retStr = test_command_433MHz->execute(test_v,&test_my_data);
418
4
    EXPECT_THAT(retStr, testing::HasSubstr("sended"));
419
4
}
420
421
TEST_F(command433MHz_Class_fixture, fakeSwitchON)
422
4
{
423
4
    test_v.push_back("show");
424
4
    test_v.push_back("all");
425
4
    std::cout << test_command_433MHz->execute(test_v,&test_my_data) <<std::endl;
426
4
    auto v = test_rec->getSwitchPointerVector();
427
4
    EXPECT_EQ(v.size(),5);
428
4
    test_v.clear();
429
4
    test_v.push_back("433MHz");
430
4
    test_v.push_back("switch");
431
4
    test_v.push_back("ALARM-fake");
432
4
    test_v.push_back("ON");
433
4
434
4
    std::string retStr = test_command_433MHz->execute(test_v,&test_my_data);
435
4
    EXPECT_THAT(retStr, testing::HasSubstr(" not found ALARM-fake"));
436
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_ardu_BT.cpp
Line
Count
Source
1
#include <gtest/gtest.h>
2
#include "../command_ardu.h"
3
#include "../../../functions/functions.h"
4
#include "../../../RADIO_433_eq/radio_433_eq.h"
5
#include "../../../433MHz/RFLink/rflinkhandler.h"
6
#include "../../../iDomTools/test/iDomTools_fixture.h"
7
8
class commandArdu_Class_fixture : public iDomTOOLS_ClassTest
9
{
10
public:
11
44
    commandArdu_Class_fixture() {
12
44
        this->test_RFLink = std::nullptr_t();
13
44
        this->test_ardu = std::nullptr_t();
14
44
    }
15
16
protected:
17
    std::vector<std::string> test_v= {"ardu"};
18
    RFLinkHandler* test_RFLink;
19
    blockQueue test_q;
20
    command_ardu* test_ardu;
21
    void SetUp() final
22
44
    {
23
44
        iDomTOOLS_ClassTest::SetUp();
24
44
25
44
        test_q._clearAll();
26
44
27
44
        test_RFLink = new RFLinkHandler(&test_my_data);
28
44
        test_ardu = new command_ardu("ardu", &test_my_data);
29
44
        test_my_data.main_RFLink = test_RFLink;
30
44
        test_v.push_back("433MHz");
31
44
        std::cout << "commandArdu_Class_fixture SetUp" << std::endl;
32
44
    }
33
34
    void TearDown() final
35
44
    {
36
44
        iDomTOOLS_ClassTest::TearDown();
37
44
        delete test_RFLink;
38
44
        delete test_ardu;
39
44
        std::cout << "commandArdu_Class_fixture TearDown" << std::endl;
40
44
    }
41
42
};
43
44
TEST_F(commandArdu_Class_fixture, wrongMSGformat)
45
4
{
46
4
    test_v.push_back("EV1527;ID=01e7be;SWITCH=01;CMD=ON;"); // wronh msg format missing 20;
47
4
    EXPECT_THROW(test_ardu->execute(test_v, &test_my_data), WRONG_FORMAT);
48
4
}
49
50
TEST_F(commandArdu_Class_fixture, UnlockHome)
51
4
{
52
4
    test_idomTOOLS->lockHome();
53
4
    EXPECT_EQ(test_status.getObjectState("house"),STATE::LOCK);
54
4
55
4
    test_v.push_back("20;EV1527;ID=01e7be;SWITCH=01;CMD=ON;");
56
4
    test_ardu->execute(test_v, &test_my_data);
57
4
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNLOCK);
58
4
59
4
    EXPECT_EQ(test_q._size(),1);
60
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PLAY);
61
4
    EXPECT_EQ(test_q._size(),0);
62
4
}
63
64
TEST_F(commandArdu_Class_fixture, LockHome)
65
4
{
66
4
    test_idomTOOLS->unlockHome();
67
4
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNLOCK);
68
4
69
4
    test_v.push_back("20;EV1527;ID=01e7be;SWITCH=01;CMD=ON;");
70
16
    for(auto i = 0; i < 3; ++i){
71
12
        test_ardu->execute(test_v, &test_my_data);
72
12
    }
73
4
74
4
    EXPECT_EQ(test_status.getObjectState("house"),STATE::LOCK);
75
4
    EXPECT_EQ(test_q._size(),1);
76
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::STOP);
77
4
    EXPECT_EQ(test_q._size(),0);
78
4
}
79
80
TEST_F(commandArdu_Class_fixture, playMusic)
81
4
{
82
4
    test_idomTOOLS->unlockHome();
83
4
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNLOCK);
84
4
    EXPECT_EQ(test_status.getObjectState("listwa"),STATE::UNKNOWN);
85
4
    test_status.addObject("music",STATE::STOP);
86
4
87
4
    test_v.push_back("20;EV1527;ID=01e7be;SWITCH=01;CMD=ON;");
88
4
89
4
    test_ardu->execute(test_v, &test_my_data);
90
4
91
4
    EXPECT_EQ(test_q._size(),1);
92
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PLAY);
93
4
    EXPECT_EQ(test_q._size(),0);
94
4
    EXPECT_EQ(test_status.getObjectState("listwa"),STATE::ON);
95
4
}
96
97
TEST_F(commandArdu_Class_fixture, stopMusic)
98
4
{
99
4
    test_idomTOOLS->unlockHome();
100
4
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNLOCK);
101
4
    EXPECT_EQ(test_status.getObjectState("listwa"),STATE::UNKNOWN);
102
4
    test_status.addObject("music",STATE::PLAY);
103
4
104
4
    test_v.push_back("20;EV1527;ID=01e7be;SWITCH=01;CMD=ON;");
105
4
106
4
    test_ardu->execute(test_v, &test_my_data);
107
4
108
4
    EXPECT_EQ(test_q._size(),1);
109
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::STOP);
110
4
    EXPECT_EQ(test_q._size(),0);
111
4
    EXPECT_EQ(test_status.getObjectState("listwa"),STATE::OFF);
112
4
}
113
114
TEST_F(commandArdu_Class_fixture, weatherStationTemp)
115
4
{
116
4
    test_v.push_back("20;2A;LaCrosse;ID=0704;TEMP=8043;");
117
4
    test_ardu->execute(test_v, &test_my_data);
118
4
    RADIO_WEATHER_STATION* st = static_cast<RADIO_WEATHER_STATION*>(test_my_data.main_REC->getEqPointer("first"));
119
4
    EXPECT_DOUBLE_EQ(-6.7, st->data.getTemperature() );
120
4
    EXPECT_DOUBLE_EQ(0, st->data.getHumidity() );
121
4
    test_v[2] = "20;35;LaCrosse;ID=0704;HUM=42;";
122
4
    test_ardu->execute(test_v, &test_my_data);
123
4
    EXPECT_DOUBLE_EQ(42, st->data.getHumidity() );
124
4
    test_v[2] = "20;2A;LaCrosse;ID=0704;TEMP=0000;";
125
4
    test_ardu->execute(test_v, &test_my_data);
126
4
    EXPECT_DOUBLE_EQ(0, st->data.getTemperature() );
127
4
}
128
129
TEST_F(commandArdu_Class_fixture, command_ardu_show)
130
4
{
131
4
    test_v.pop_back();
132
4
    test_v.push_back("show");
133
4
    std::string retStr = test_ardu->execute(test_v, &test_my_data);
134
4
    EXPECT_THAT(retStr, testing::HasSubstr("data: 0"));
135
4
    EXPECT_THAT(retStr, testing::HasSubstr("temperature= 0c"));
136
4
}
137
138
TEST_F(commandArdu_Class_fixture, command_ardu_help)
139
4
{
140
4
    command_ardu test_Command_ardu ("ardu");
141
4
142
4
    std::string retStr = test_Command_ardu.help();
143
4
    EXPECT_STREQ(retStr.c_str(), " only for internal usege\n");
144
4
}
145
146
TEST_F(commandArdu_Class_fixture, command_ardu_433MHz_throw)
147
4
{
148
4
    test_v.push_back("fake_msg");
149
4
    std::string retStr = test_ardu->execute(test_v, &test_my_data);
150
4
151
4
    EXPECT_THAT(retStr, testing::HasSubstr("for"));
152
4
}
153
154
TEST_F(commandArdu_Class_fixture, command_ardu_433MHz_OK)
155
4
{
156
4
    test_v.push_back("20;53;OK;");
157
4
    test_ardu->execute(test_v, &test_my_data);
158
4
    EXPECT_NE(test_my_data.main_RFLink->okTime, 0);
159
4
    EXPECT_EQ(test_my_data.main_RFLink->okTime, Clock::getUnixTime());
160
4
}
161
162
TEST_F(commandArdu_Class_fixture, command_ardu_433MHz_PING)
163
4
{
164
4
    test_v.push_back("20;99;PONG;");
165
4
    test_ardu->execute(test_v, &test_my_data);
166
4
    EXPECT_NE(test_my_data.main_RFLink->pingTime, 0);
167
4
    EXPECT_EQ(test_my_data.main_RFLink->pingTime, Clock::getUnixTime());
168
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_big_BT.cpp
Line
Count
Source
1
#include "../command_big.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_big_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_big_Class_fixture()
8
4
    {
9
4
10
4
    }
11
12
protected:
13
    std::unique_ptr<command_big> test_command_big;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
4
    {
18
4
        iDomTOOLS_ClassTest::SetUp();
19
4
        test_command_big = std::make_unique <command_big> ("big");
20
4
    }
21
22
    void TearDown() final
23
4
    {
24
4
        iDomTOOLS_ClassTest::TearDown();
25
4
    }
26
};
27
28
TEST_F(command_big_Class_fixture, main)
29
4
{
30
4
    int s = 55;
31
4
    test_v.push_back("big");
32
4
    test_v.push_back(std::to_string(s));
33
4
    auto ret = test_command_big->execute(test_v,&test_my_data);
34
4
    EXPECT_EQ(ret.size(),s);
35
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_clock_BT.cpp
Line
Count
Source
1
#include "../command_clock.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_clock_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_clock_Class_fixture()
8
8
    {
9
8
10
8
    }
11
12
protected:
13
    std::unique_ptr<command_clock> test_command_clock;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
8
    {
18
8
        iDomTOOLS_ClassTest::SetUp();
19
8
        test_command_clock = std::make_unique <command_clock> ("clock");
20
8
    }
21
22
    void TearDown() final
23
8
    {
24
8
        iDomTOOLS_ClassTest::TearDown();
25
8
    }
26
};
27
28
TEST_F(command_clock_Class_fixture, main)
29
4
{
30
4
    test_v.push_back("clock");
31
4
    test_v.push_back("1234");
32
4
    auto ret = test_command_clock->execute(test_v,&test_my_data);
33
4
    EXPECT_STREQ(ret.c_str(),"clock set return test");
34
4
}
35
36
TEST_F(command_clock_Class_fixture, missingParamiter)
37
4
{
38
4
    test_v.push_back("clock");
39
4
    auto ret = test_command_clock->execute(test_v,&test_my_data);
40
4
    EXPECT_STREQ(ret.c_str(),"can not set clock");
41
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_cmd_BT.cpp
Line
Count
Source
1
#include "../command_cmd.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_cmd_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_cmd_Class_fixture()
8
8
    {
9
8
10
8
    }
11
12
protected:
13
    std::unique_ptr<command_cmd> test_command_cmd;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
8
    {
18
8
        iDomTOOLS_ClassTest::SetUp();
19
8
        test_command_cmd = std::make_unique <command_cmd> ("cmd");
20
8
    }
21
22
    void TearDown() final
23
8
    {
24
8
        iDomTOOLS_ClassTest::TearDown();
25
8
    }
26
};
27
28
TEST_F(command_cmd_Class_fixture, main)
29
4
{
30
4
    test_my_data.server_settings->omxplayerFile = "/mnt/ramdisk/cmd";
31
4
    test_v.push_back("cmd");
32
4
    auto ret = test_command_cmd->execute(test_v,&test_my_data);
33
4
    EXPECT_THAT(ret, ::testing::HasSubstr("fifo file contain:"));
34
4
}
35
36
TEST_F(command_cmd_Class_fixture, wrongParamiter)
37
4
{
38
4
    test_v.push_back("cmd");
39
4
    test_v.push_back("1234");
40
4
    auto ret = test_command_cmd->execute(test_v,&test_my_data);
41
4
    EXPECT_STREQ(ret.c_str(),"error: unknown parameter: 1234");
42
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_event_BT.cpp
Line
Count
Source
1
#include "../command_event.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_event_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_event_Class_fixture()
8
24
    {
9
24
10
24
    }
11
12
protected:
13
    std::unique_ptr<command_event> test_command_event;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
24
    {
18
24
        iDomTOOLS_ClassTest::SetUp();
19
24
        test_command_event = std::make_unique <command_event> ("event");
20
24
    }
21
22
    void TearDown() final
23
24
    {
24
24
        iDomTOOLS_ClassTest::TearDown();
25
24
    }
26
};
27
28
TEST_F(command_event_Class_fixture, eventList)
29
4
{
30
4
    test_v.push_back("event");
31
4
    auto ret = test_command_event->execute(test_v,&test_my_data);
32
4
    EXPECT_THAT(ret, ::testing::HasSubstr("pilot"));
33
4
}
34
35
TEST_F(command_event_Class_fixture, eventPilot)
36
4
{
37
4
    test_v.push_back("event");
38
4
    test_v.push_back("pilot");
39
4
    auto ret = test_command_event->execute(test_v,&test_my_data);
40
4
    EXPECT_THAT(ret, ::testing::HasSubstr("pilot"));
41
4
}
42
43
TEST_F(command_event_Class_fixture, clearEventPilot)
44
4
{
45
4
    test_my_data.myEventHandler.run("pilot")->addEvent("pilot test");
46
4
    EXPECT_EQ(test_my_data.myEventHandler.run("pilot")->howManyEvent(),1);
47
4
    test_v.push_back("event");
48
4
    test_v.push_back("pilot");
49
4
    test_v.push_back("clear");
50
4
    test_command_event->execute(test_v,&test_my_data);
51
4
    EXPECT_EQ(test_my_data.myEventHandler.run("pilot")->howManyEvent(),0);
52
4
}
53
54
TEST_F(command_event_Class_fixture, clearsSomeEventPilot)
55
4
{
56
44
    for(int i = 0; i<10; ++i){
57
40
    test_my_data.myEventHandler.run("pilot")->addEvent("pilot test");
58
40
    }
59
4
    EXPECT_EQ(test_my_data.myEventHandler.run("pilot")->howManyEvent(),10);
60
4
    test_v.push_back("event");
61
4
    test_v.push_back("pilot");
62
4
    test_v.push_back("clear");
63
4
    test_v.push_back("3");
64
4
    test_v.push_back("6");
65
4
    test_command_event->execute(test_v,&test_my_data);
66
4
    EXPECT_EQ(test_my_data.myEventHandler.run("pilot")->howManyEvent(),7);
67
4
}
68
69
TEST_F(command_event_Class_fixture, intensityEventPilot)
70
4
{
71
4
    test_my_data.myEventHandler.run("pilot")->addEvent("pilot test");
72
4
    EXPECT_EQ(test_my_data.myEventHandler.run("pilot")->howManyEvent(),1);
73
4
    test_v.push_back("event");
74
4
    test_v.push_back("pilot");
75
4
    test_v.push_back("intensity");
76
4
    auto ret = test_command_event->execute(test_v,&test_my_data);
77
4
    EXPECT_STREQ(ret.c_str(),"event pilot 1 intensity per last minute!");
78
4
    EXPECT_EQ(test_my_data.myEventHandler.run("pilot")->howManyEvent(),1);
79
4
}
80
81
TEST_F(command_event_Class_fixture, wrongParamiter)
82
4
{
83
4
    test_v.push_back("event");
84
4
    test_v.push_back("pilot");
85
4
    test_v.push_back("clear");
86
4
    test_v.push_back("3");
87
4
    test_v.push_back("6");
88
4
    test_v.push_back("clear");
89
4
    test_v.push_back("3");
90
4
    test_v.push_back("6");
91
4
    test_v.push_back("clear");
92
4
    test_v.push_back("3");
93
4
    test_v.push_back("6");
94
4
    auto ret = test_command_event->execute(test_v,&test_my_data);
95
4
    EXPECT_THAT(ret,::testing::HasSubstr("event"));
96
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_exit_BT.cpp
Line
Count
Source
1
#include "../commandexit.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_exit_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_exit_Class_fixture()
8
4
    {
9
4
10
4
    }
11
12
protected:
13
    std::unique_ptr<commandEXIT> test_command_exit;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
4
    {
18
4
        iDomTOOLS_ClassTest::SetUp();
19
4
        test_command_exit = std::make_unique <commandEXIT> ("exit");
20
4
    }
21
22
    void TearDown() final
23
4
    {
24
4
        iDomTOOLS_ClassTest::TearDown();
25
4
    }
26
};
27
28
TEST_F(command_exit_Class_fixture, main)
29
4
{
30
4
    test_v.push_back("exit");
31
4
    auto ret = test_command_exit->execute(test_v,&test_my_data);
32
4
    EXPECT_STREQ(ret.c_str(),"\nEND.\n");
33
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_hello_BT.cpp
Line
Count
Source
1
#include "../command_hello.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_hello_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_hello_Class_fixture()
8
4
    {
9
4
10
4
    }
11
12
protected:
13
    std::unique_ptr<command_hello> test_command_hello;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
4
    {
18
4
        iDomTOOLS_ClassTest::SetUp();
19
4
        test_command_hello = std::make_unique <command_hello> ("hello");
20
4
    }
21
22
    void TearDown() final
23
4
    {
24
4
        iDomTOOLS_ClassTest::TearDown();
25
4
    }
26
};
27
28
TEST_F(command_hello_Class_fixture, main)
29
4
{
30
4
    test_v.push_back("hello");
31
4
    auto ret = test_command_hello->execute(test_v,&test_my_data);
32
4
    EXPECT_STREQ(ret.c_str(),"\nHI You User!\n");
33
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_help_BT.cpp
Line
Count
Source
1
#include "../command_help.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_help_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_help_Class_fixture()
8
12
    {
9
12
10
12
    }
11
12
protected:
13
    std::unique_ptr<command_help> test_command_help;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
12
    {
18
12
        iDomTOOLS_ClassTest::SetUp();
19
12
        test_command_help = std::make_unique <command_help> ("help");
20
12
    }
21
22
    void TearDown() final
23
12
    {
24
12
        iDomTOOLS_ClassTest::TearDown();
25
12
    }
26
};
27
28
TEST_F(command_help_Class_fixture, all)
29
4
{
30
4
    std::unique_ptr<commandHandlerRoot> chr = std::make_unique<commandHandlerRoot>(&test_my_data);
31
4
    test_v.push_back("help");
32
4
    auto size = test_command_help->execute(test_v,&test_my_data).size();
33
4
    EXPECT_EQ(size,4424);
34
4
}
35
36
TEST_F(command_help_Class_fixture, one)
37
4
{
38
4
    std::unique_ptr<commandHandlerRoot> chr = std::make_unique<commandHandlerRoot>(&test_my_data);
39
4
    test_v.push_back("help");
40
4
    test_v.push_back("ok");
41
4
    auto ret = test_command_help->execute(test_v,&test_my_data);
42
4
    EXPECT_STREQ(ret.c_str(),"ok - confirmation msg server response: END \n");
43
4
}
44
45
TEST_F(command_help_Class_fixture, nonExistingCommand)
46
4
{
47
4
    std::unique_ptr<commandHandlerRoot> chr = std::make_unique<commandHandlerRoot>(&test_my_data);
48
4
    test_v.push_back("help");
49
4
    test_v.push_back("okdoki");
50
4
    auto ret = test_command_help->execute(test_v,&test_my_data);
51
4
    EXPECT_STREQ(ret.c_str(),"unknown command: okdoki help note not found");
52
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_idom_BT.cpp
Line
Count
Source
1
#include <gtest/gtest.h>
2
3
#include "../command_idom.h"
4
#include "../../../functions/functions.h"
5
#include "../../../RADIO_433_eq/radio_433_eq.h"
6
#include "../../../433MHz/RFLink/rflinkhandler.h"
7
#include "../../../iDomTools/test/iDomTools_fixture.h"
8
#include "../../../thread_functions/iDom_thread.h"
9
10
class commandiDom_Class_fixture : public iDomTOOLS_ClassTest
11
{
12
public:
13
    commandiDom_Class_fixture()
14
80
    {
15
80
        this->test_command_iDom = std::nullptr_t();
16
80
        this->test_RFLink = std::nullptr_t();
17
80
    }
18
19
protected:
20
    std::vector<std::string> test_v= {"iDom"};
21
    RFLinkHandler* test_RFLink;
22
    blockQueue test_q;
23
    command_iDom* test_command_iDom;
24
25
    void SetUp() final
26
80
    {
27
80
        iDomTOOLS_ClassTest::SetUp();
28
80
29
80
        test_q._clearAll();
30
80
31
80
        test_RFLink = new RFLinkHandler(&test_my_data);
32
80
        test_command_iDom = new command_iDom("iDom");
33
80
        test_my_data.main_RFLink = test_RFLink;
34
80
        std::cout << "commandiDom_Class_fixture SetUp" << std::endl;
35
80
    }
36
37
    void TearDown() final
38
80
    {
39
80
        iDomTOOLS_ClassTest::TearDown();
40
80
        delete test_RFLink;
41
80
        delete test_command_iDom;
42
80
        std::cout << "commandiDom_Class_fixture TearDown" << std::endl;
43
80
    }
44
};
45
46
TEST_F(commandiDom_Class_fixture, getName)
47
4
{
48
4
    EXPECT_THAT(test_command_iDom->getCommandName(),testing::HasSubstr("iDom"));
49
4
}
50
51
TEST_F(commandiDom_Class_fixture, help)
52
4
{
53
4
    std::string helpStr = test_command_iDom->help();
54
4
    EXPECT_THAT(helpStr,testing::HasSubstr("iDom"));
55
4
    std::cout << "test " << helpStr.size() << std::endl;
56
4
    EXPECT_EQ(helpStr.size(),1189);
57
4
}
58
59
TEST_F(commandiDom_Class_fixture, less_param)
60
4
{
61
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
62
4
    EXPECT_THAT(retStr,testing::HasSubstr("need parameter!"));
63
4
}
64
TEST_F(commandiDom_Class_fixture, unknonw_para)
65
4
{
66
4
    test_v.push_back("fake");
67
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
68
4
    EXPECT_THAT(retStr,testing::HasSubstr("iDom - unknown parameter:"));
69
4
}
70
71
TEST_F(commandiDom_Class_fixture, speakers)
72
4
{
73
4
    test_my_data.main_iDomTools->unlockHome();
74
4
    //////////////// fake command
75
4
    test_v.push_back("speakers");
76
4
    test_v.push_back("fake");
77
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
78
4
    EXPECT_THAT(retStr,testing::HasSubstr("unknow speakers action: fake"));
79
4
    ///////////////// ON
80
4
    test_my_data.main_iDomStatus->setObjectState("speakers",STATE::UNDEFINE);
81
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("speakers"), STATE::UNDEFINE);
82
4
    test_v.clear();
83
4
    test_v.push_back("iDom");
84
4
    test_v.push_back("speakers");
85
4
    test_v.push_back("ON");
86
4
    retStr = test_command_iDom->execute(test_v, &test_my_data);
87
4
    EXPECT_THAT(retStr,testing::HasSubstr("speakers ON"));
88
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("speakers"), STATE::ON);
89
4
    ///////////////// OFF
90
4
    test_v.clear();
91
4
    test_v.push_back("iDom");
92
4
    test_v.push_back("speakers");
93
4
    test_v.push_back("OFF");
94
4
    retStr = test_command_iDom->execute(test_v, &test_my_data);
95
4
    EXPECT_THAT(retStr,testing::HasSubstr("speakers OFF"));
96
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("speakers"), STATE::OFF);
97
4
}
98
99
TEST_F(commandiDom_Class_fixture, sunset_sunrise)
100
4
{
101
4
    test_v.clear();
102
4
    test_v.push_back("iDom");
103
4
    test_v.push_back("sunset");
104
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
105
4
    std::cout << "retString: " << retStr << std::endl;
106
4
    EXPECT_THAT(retStr,testing::HasSubstr("Sunset time:"));
107
4
108
4
    test_v.clear();
109
4
    test_v.push_back("iDom");
110
4
    test_v.push_back("sunrise");
111
4
    retStr = test_command_iDom->execute(test_v, &test_my_data);
112
4
    std::cout << "retString: " << retStr << std::endl;
113
4
    EXPECT_THAT(retStr,testing::HasSubstr("Sunrise time:"));
114
4
}
115
116
TEST_F(commandiDom_Class_fixture, day_lenght)
117
4
{
118
4
    test_v.clear();
119
4
    test_v.push_back("iDom");
120
4
    test_v.push_back("day");
121
4
    test_v.push_back("lenght");
122
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
123
4
    std::cout << "retString: " << retStr << std::endl;
124
4
    EXPECT_THAT(retStr,testing::HasSubstr("Day Lenght :"));
125
4
}
126
127
TEST_F(commandiDom_Class_fixture, sun)
128
4
{
129
4
    test_v.clear();
130
4
    test_v.push_back("iDom");
131
4
    test_v.push_back("sun");
132
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
133
4
    std::cout << "retString: " << retStr << std::endl;
134
4
    EXPECT_THAT(retStr,testing::HasSubstr("Day Lenght :"));
135
4
}
136
137
TEST_F(commandiDom_Class_fixture, sysinfo)
138
4
{
139
4
    test_v.clear();
140
4
    test_v.push_back("iDom");
141
4
    test_v.push_back("sysinfo");
142
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
143
4
    std::cout << "retString: " << retStr << std::endl;
144
4
    EXPECT_THAT(retStr,testing::HasSubstr("free RAM"));
145
4
}
146
147
TEST_F(commandiDom_Class_fixture, temperature)
148
4
{
149
4
    TEST_DATA::return_send_to_arduino = "-12:22";
150
4
    test_v.clear();
151
4
    test_v.push_back("iDom");
152
4
    test_v.push_back("temperature");
153
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
154
4
    std::cout << "retString: " << retStr << std::endl;
155
4
    EXPECT_THAT(retStr,testing::HasSubstr("-12:22"));
156
4
157
4
    test_v.clear();
158
4
    test_v.push_back("iDom");
159
4
    test_v.push_back("temperature");
160
4
    test_v.push_back("stats");
161
4
    test_v.push_back("insideee");
162
4
    retStr = test_command_iDom->execute(test_v, &test_my_data);
163
4
    std::cout << "retString: " << retStr << std::endl;
164
4
    EXPECT_THAT(retStr,testing::HasSubstr("not found!"));
165
4
}
166
167
TEST_F(commandiDom_Class_fixture, text)
168
4
{
169
4
    TEST_DATA::return_send_to_arduino = "-12:22";
170
4
    test_v.clear();
171
4
    test_v.push_back("iDom");
172
4
    test_v.push_back("text");
173
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
174
4
    std::cout << "retString: " << retStr << std::endl;
175
4
    EXPECT_THAT(retStr,testing::HasSubstr("Godzina"));
176
4
}
177
178
TEST_F(commandiDom_Class_fixture, lock_unlock)
179
4
{
180
4
    test_v.clear();
181
4
    test_v.push_back("iDom");
182
4
    test_v.push_back("lock");
183
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
184
4
    std::cout << "retString: " << retStr << std::endl;
185
4
    EXPECT_EQ(test_my_data.idom_all_state.houseState, STATE::LOCK);
186
4
187
4
    test_v.clear();
188
4
    test_v.push_back("iDom");
189
4
    test_v.push_back("unlock");
190
4
    retStr = test_command_iDom->execute(test_v, &test_my_data);
191
4
    std::cout << "retString: " << retStr << std::endl;
192
4
    EXPECT_EQ(test_my_data.idom_all_state.houseState, STATE::UNLOCK);
193
4
}
194
195
TEST_F(commandiDom_Class_fixture, t_230V)
196
4
{
197
4
    test_my_data.main_iDomTools->unlockHome();
198
4
    //////////////// fake command
199
4
    test_v.push_back("230V");
200
4
    test_v.push_back("fake");
201
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
202
4
    EXPECT_THAT(retStr,testing::HasSubstr("wrong paramiter"));
203
4
    ///////////////// ON
204
4
    test_my_data.main_iDomStatus->setObjectState("printer",STATE::UNDEFINE);
205
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("printer"), STATE::UNDEFINE);
206
4
    test_v.clear();
207
4
    test_v.push_back("iDom");
208
4
    test_v.push_back("230V");
209
4
    test_v.push_back("ON");
210
4
    retStr = test_command_iDom->execute(test_v, &test_my_data);
211
4
    std::cout << "retString: " << retStr << std::endl;
212
4
    EXPECT_THAT(retStr,testing::HasSubstr("230V ON"));
213
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("printer"), STATE::ON);
214
4
    ///////////////// OFF
215
4
    test_v.clear();
216
4
    test_v.push_back("iDom");
217
4
    test_v.push_back("230V");
218
4
    test_v.push_back("OFF");
219
4
    retStr = test_command_iDom->execute(test_v, &test_my_data);
220
4
    std::cout << "retString: " << retStr << std::endl;
221
4
    EXPECT_THAT(retStr,testing::HasSubstr("230V OFF"));
222
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("printer"), STATE::OFF);
223
4
}
224
225
TEST_F(commandiDom_Class_fixture, smog)
226
4
{
227
4
    test_v.clear();
228
4
    test_v.push_back("iDom");
229
4
    test_v.push_back("smog");
230
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
231
4
    std::cout << "retString: " << retStr << std::endl;
232
4
    EXPECT_THAT(retStr,testing::HasSubstr(" mg/m^3"));
233
4
}
234
235
TEST_F(commandiDom_Class_fixture, say)
236
4
{
237
4
    Clock::setTime_forBT_usage(23,23);
238
4
    TEST_DATA::return_send_to_arduino = "-3:6";
239
4
    test_v.clear();
240
4
    test_v.push_back("iDom");
241
4
    test_v.push_back("say");
242
4
    test_v.push_back("dummy");
243
4
    test_v.push_back("dummy");
244
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
245
4
    std::cout << "retString: " << retStr << std::endl;
246
4
    //EXPECT_THAT(retStr,testing::HasSubstr("sad"));
247
4
}
248
TEST_F(commandiDom_Class_fixture, wifi)
249
4
{
250
4
    TEST_DATA::return_httpPost = "ok";
251
4
    test_v.clear();
252
4
    test_v.push_back("iDom");
253
4
    test_v.push_back("wifi");
254
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
255
4
    std::cout << "retString: " << retStr << std::endl;
256
4
    EXPECT_THAT(retStr,testing::HasSubstr("ok"));
257
4
}
258
259
TEST_F(commandiDom_Class_fixture, lightning)
260
4
{
261
4
    test_v.clear();
262
4
    test_v.push_back("iDom");
263
4
    test_v.push_back("lightning");
264
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
265
4
    std::cout << "retString: " << retStr << std::endl;
266
4
    EXPECT_THAT(retStr,testing::HasSubstr("bool: "));
267
4
}
268
269
TEST_F(commandiDom_Class_fixture, camera)
270
4
{
271
4
    test_my_data.server_settings->cameraLedOFF = "cameraOFF";
272
4
    test_my_data.server_settings->cameraLedON = "cameraON";
273
4
274
4
    Clock::setTime_forBT_usage(23,23);
275
4
    test_v.clear();
276
4
    test_v.push_back("iDom");
277
4
    test_v.push_back("camera");
278
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
279
4
    std::cout << "retString: " << retStr << std::endl;
280
4
    EXPECT_STREQ(retStr.c_str(),"not enough parameters");
281
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("cameraLED"),STATE::UNKNOWN);
282
4
    ////////////////////////////////////////// ON
283
4
    TEST_DATA::return_httpPost = "ok.\n";
284
4
    test_v.clear();
285
4
    test_v.push_back("iDom");
286
4
    test_v.push_back("camera");
287
4
    test_v.push_back("LED");
288
4
289
4
    test_v.push_back("ON");
290
4
    retStr = test_command_iDom->execute(test_v, &test_my_data);
291
4
    std::cout << "retString: " << retStr << std::endl;
292
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("cameraLED"),STATE::ON);
293
4
    EXPECT_STREQ(retStr.c_str(),"led DONE");
294
4
    ////////////////////////////////////////// OFF
295
4
    TEST_DATA::return_httpPost = "ok.\n";
296
4
    test_v.clear();
297
4
    test_v.push_back("iDom");
298
4
    test_v.push_back("camera");
299
4
    test_v.push_back("LED");
300
4
301
4
    test_v.push_back("OFF");
302
4
    retStr = test_command_iDom->execute(test_v, &test_my_data);
303
4
    std::cout << "retString: " << retStr << std::endl;
304
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("cameraLED"),STATE::OFF);
305
4
    EXPECT_STREQ(retStr.c_str(),"led DONE");
306
4
}
307
308
TEST_F(commandiDom_Class_fixture, LED)
309
4
{
310
4
    test_my_data.main_iDomTools->unlockHome();
311
4
312
4
    test_v.clear();
313
4
    test_v.push_back("iDom");
314
4
    test_v.push_back("LED");
315
4
    test_v.push_back("33");
316
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
317
4
    std::cout << "retString: " << retStr << std::endl;
318
4
    EXPECT_THAT(retStr,testing::HasSubstr("need more parameter from-to-R-G-B"));
319
4
320
4
    ///////////////////////////////////// OFF
321
4
    TEST_DATA::return_send_to_arduino = "led OFF";
322
4
323
4
    test_v.clear();
324
4
    test_v.push_back("iDom");
325
4
    test_v.push_back("LED");
326
4
    test_v.push_back("OFF");
327
4
    retStr = test_command_iDom->execute(test_v, &test_my_data);
328
4
    std::cout << "retString: " << retStr << std::endl;
329
4
    EXPECT_THAT(retStr,testing::HasSubstr("led OFF"));
330
4
}
331
TEST_F(commandiDom_Class_fixture, kodi)
332
4
{
333
4
    test_my_data.main_iDomStatus->setObjectState("KODI",STATE::ACTIVE);
334
4
    test_v.clear();
335
4
    test_v.push_back("iDom");
336
4
    test_v.push_back("KODI");
337
4
    std::string retStr = test_command_iDom->execute(test_v, &test_my_data);
338
4
339
4
    std::cout << "retString: " << retStr << std::endl;
340
4
    EXPECT_STREQ(retStr.c_str(),"kodi already run");
341
4
342
4
    test_my_data.main_iDomStatus->setObjectState("KODI",STATE::DEACTIVE);
343
4
    test_my_data.main_iDomStatus->setObjectState("music",STATE::PLAY);
344
4
    test_my_data.main_iDomStatus->setObjectState("speakers",STATE::ON);
345
4
346
4
    std::array<Thread_array_struc,iDomConst::MAX_CONNECTION> test_ThreadArrayStruc;
347
4
348
44
    for (int i = 0 ; i < iDomConst::MAX_CONNECTION; i++)
349
40
        test_ThreadArrayStruc.at(i).thread_socket = 0;
350
4
    //test_ThreadArrayStruc.at(3).thread_socket = 0;
351
4
    test_my_data.main_THREAD_arr = &test_ThreadArrayStruc;
352
4
353
4
    test_v.clear();
354
4
    test_v.push_back("iDom");
355
4
    test_v.push_back("KODI");
356
4
    retStr = test_command_iDom->execute(test_v, &test_my_data);
357
4
358
4
    //sleep(1);
359
4
    iDOM_THREAD::waitUntilAllThreadEnd(&test_my_data);
360
4
361
4
    std::cout << "retString: " << retStr << std::endl;
362
4
    EXPECT_THAT(retStr,testing::HasSubstr("STARTED"));
363
4
364
44
    for (int i = 0 ; i < iDomConst::MAX_CONNECTION; i++)
365
40
        test_ThreadArrayStruc[i].thread_socket = -1;
366
4
    test_v.clear();
367
4
    test_v.push_back("iDom");
368
4
    test_v.push_back("KODI");
369
4
    retStr = test_command_iDom->execute(test_v, &test_my_data);
370
4
371
4
    std::cout << "retString: " << retStr << std::endl;
372
4
    EXPECT_STREQ(retStr.c_str(),"not free space to new thread");
373
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_ip_BT.cpp
Line
Count
Source
1
#include "../command_ip.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_ip_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_ip_Class_fixture()
8
4
    {
9
4
10
4
    }
11
12
protected:
13
    std::unique_ptr<command_ip> test_command_ip;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
4
    {
18
4
        iDomTOOLS_ClassTest::SetUp();
19
4
        test_command_ip =  std::make_unique <command_ip> ("ip");
20
4
    }
21
22
    void TearDown() final
23
4
    {
24
4
        iDomTOOLS_ClassTest::TearDown();
25
4
    }
26
};
27
28
TEST_F(command_ip_Class_fixture, main)
29
4
{
30
4
    test_my_data.server_settings->SERVER_IP = "100.001.1.0";
31
4
    test_v.push_back("ip");
32
4
    auto ret = test_command_ip->execute(test_v,&test_my_data);
33
4
    EXPECT_STREQ(ret.c_str(),"iDom server IP: 100.001.1.0");
34
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_log_BT.cpp
Line
Count
Source
1
#include "../command_log.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_log_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_log_Class_fixture()
8
4
    {
9
4
10
4
    }
11
12
protected:
13
    std::unique_ptr<command_log> test_command_log;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
4
    {
18
4
        iDomTOOLS_ClassTest::SetUp();
19
4
        test_command_log = std::make_unique <command_log> ("log");
20
4
    }
21
22
    void TearDown() final
23
4
    {
24
4
        iDomTOOLS_ClassTest::TearDown();
25
4
    }
26
};
27
28
TEST_F(command_log_Class_fixture, main)
29
4
{
30
4
    test_v.clear();
31
4
    test_v.push_back("log");
32
4
    test_v.push_back("INFOoo");
33
4
    test_v.push_back("test");
34
4
    auto ret = test_command_log->execute(test_v,&test_my_data);
35
4
    EXPECT_THAT(ret, ::testing::HasSubstr("DONE!"));
36
4
37
4
    test_v.clear();
38
4
    test_v.push_back("log");
39
4
    test_v.push_back("INFO");
40
4
    test_v.push_back("test");
41
4
    ret = test_command_log->execute(test_v,&test_my_data);
42
4
    EXPECT_THAT(ret, ::testing::HasSubstr("DONE!"));
43
4
44
4
    test_v.clear();
45
4
    test_v.push_back("log");
46
4
    test_v.push_back("DEBUG");
47
4
    test_v.push_back("test");
48
4
    ret = test_command_log->execute(test_v,&test_my_data);
49
4
    EXPECT_THAT(ret, ::testing::HasSubstr("DONE!"));
50
4
51
4
    test_v.clear();
52
4
    test_v.push_back("log");
53
4
    test_v.push_back("WARNING");
54
4
    test_v.push_back("test");
55
4
    ret = test_command_log->execute(test_v,&test_my_data);
56
4
    EXPECT_THAT(ret, ::testing::HasSubstr("DONE!"));
57
4
    test_v.clear();
58
4
    test_v.push_back("log");
59
4
    test_v.push_back("ERROR");
60
4
    test_v.push_back("test");
61
4
    ret = test_command_log->execute(test_v,&test_my_data);
62
4
    EXPECT_THAT(ret, ::testing::HasSubstr("DONE!"));
63
4
    test_v.clear();
64
4
    test_v.push_back("log");
65
4
    test_v.push_back("FATAL");
66
4
    test_v.push_back("test");
67
4
    ret = test_command_log->execute(test_v,&test_my_data);
68
4
    EXPECT_THAT(ret, ::testing::HasSubstr("DONE!"));
69
4
    test_v.clear();
70
4
    test_v.push_back("log");
71
4
    test_v.push_back("CRITICAL");
72
4
    test_v.push_back("test");
73
4
    ret = test_command_log->execute(test_v,&test_my_data);
74
4
    EXPECT_THAT(ret, ::testing::HasSubstr("DONE!"));
75
4
    test_v.clear();
76
4
    test_v.push_back("log");
77
4
    test_v.push_back("VERBOSE");
78
4
    test_v.push_back("test");
79
4
    ret = test_command_log->execute(test_v,&test_my_data);
80
4
    EXPECT_THAT(ret, ::testing::HasSubstr("DONE!"));
81
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_mpd_BT.cpp
Line
Count
Source
1
#include "../command_mpd.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_mpd_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_mpd_Class_fixture()
8
36
    {
9
36
10
36
    }
11
12
protected:
13
    std::unique_ptr<command_mpd> test_command_mpd;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
36
    {
18
36
        iDomTOOLS_ClassTest::SetUp();
19
36
        test_command_mpd = std::make_unique <command_mpd> ("mpd");
20
36
    }
21
22
    void TearDown() final
23
36
    {
24
36
        iDomTOOLS_ClassTest::TearDown();
25
36
    }
26
};
27
28
TEST_F(command_mpd_Class_fixture, unknownParameter)
29
4
{
30
4
    test_v.clear();
31
4
    test_v.push_back("mpd");
32
4
    test_v.push_back("test");
33
4
    auto ret = test_command_mpd->execute(test_v,&test_my_data);
34
4
    EXPECT_STREQ(ret.c_str(), "unknown parameter test");
35
4
36
4
 }
37
38
TEST_F(command_mpd_Class_fixture, list)
39
4
{
40
4
    test_my_data.ptr_MPD_info->songList = {"song 1","song 2","song 3"};
41
4
    test_v.clear();
42
4
    test_v.push_back("mpd");
43
4
    test_v.push_back("list");
44
4
    auto ret = test_command_mpd->execute(test_v,&test_my_data);
45
4
    EXPECT_STREQ(ret.c_str(), "song 1\nsong 2\nsong 3\n");
46
4
 }
47
48
TEST_F(command_mpd_Class_fixture, get)
49
4
{
50
4
    test_my_data.ptr_MPD_info->volume = 33;
51
4
    test_my_data.ptr_MPD_info->radio = "radio test";
52
4
    test_my_data.ptr_MPD_info->title = "title test";
53
4
54
4
    test_v.clear();
55
4
    test_v.push_back("mpd");
56
4
    test_v.push_back("get");
57
4
    test_v.push_back("volume");
58
4
59
4
    auto ret = test_command_mpd->execute(test_v,&test_my_data);
60
4
    EXPECT_STREQ(ret.c_str(), "33");
61
4
62
4
    test_v.clear();
63
4
    test_v.push_back("mpd");
64
4
    test_v.push_back("get");
65
4
    test_v.push_back("info");
66
4
67
4
    ret = test_command_mpd->execute(test_v,&test_my_data);
68
4
    EXPECT_STREQ(ret.c_str(), "radio test : title test");
69
4
 }
70
TEST_F(command_mpd_Class_fixture, volume)
71
4
{
72
4
    test_my_data.ptr_MPD_info->volume = 33;
73
4
74
4
    test_v.clear();
75
4
    test_v.push_back("mpd");
76
4
    test_v.push_back("volume");
77
4
    test_v.push_back("up");
78
4
79
4
    blockQueue test_q;
80
4
    test_q._clearAll();
81
4
82
4
    test_command_mpd->execute(test_v,&test_my_data);
83
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::VOLUP);
84
4
85
4
    test_v.clear();
86
4
    test_v.push_back("mpd");
87
4
    test_v.push_back("volume");
88
4
    test_v.push_back("down");
89
4
90
4
    test_command_mpd->execute(test_v,&test_my_data);
91
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::VOLDOWN);
92
4
93
4
    test_v.clear();
94
4
    test_v.push_back("mpd");
95
4
    test_v.push_back("volume");
96
4
    test_v.push_back("55");
97
4
98
4
    test_command_mpd->execute(test_v,&test_my_data);
99
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::VOLSET);
100
4
    EXPECT_EQ(test_my_data.ptr_MPD_info->volume, 55);
101
4
    /////// voule -gt 100%
102
4
    test_v.clear();
103
4
    test_v.push_back("mpd");
104
4
    test_v.push_back("volume");
105
4
    test_v.push_back("155");
106
4
107
4
    test_command_mpd->execute(test_v,&test_my_data);
108
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::NULL_);
109
4
    EXPECT_EQ(test_my_data.ptr_MPD_info->volume, 55);
110
4
 }
111
112
TEST_F(command_mpd_Class_fixture, pause)
113
4
{
114
4
    test_v.clear();
115
4
    test_v.push_back("mpd");
116
4
    test_v.push_back("pause");
117
4
118
4
    blockQueue test_q;
119
4
    test_q._clearAll();
120
4
121
4
    auto ret = test_command_mpd->execute(test_v,&test_my_data);
122
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PAUSE);
123
4
    EXPECT_STREQ(ret.c_str(), "paused!");
124
4
}
125
126
TEST_F(command_mpd_Class_fixture, next)
127
4
{
128
4
    test_v.clear();
129
4
    test_v.push_back("mpd");
130
4
    test_v.push_back("next");
131
4
132
4
    blockQueue test_q;
133
4
    test_q._clearAll();
134
4
135
4
    test_command_mpd->execute(test_v,&test_my_data);
136
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::NEXT);
137
4
}
138
139
TEST_F(command_mpd_Class_fixture, prev)
140
4
{
141
4
    test_v.clear();
142
4
    test_v.push_back("mpd");
143
4
    test_v.push_back("prev");
144
4
145
4
    blockQueue test_q;
146
4
    test_q._clearAll();
147
4
148
4
    test_command_mpd->execute(test_v,&test_my_data);
149
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PREV);
150
4
}
151
152
TEST_F(command_mpd_Class_fixture, stop)
153
4
{
154
4
    test_v.clear();
155
4
    test_v.push_back("mpd");
156
4
    test_v.push_back("stop");
157
4
158
4
    blockQueue test_q;
159
4
    test_q._clearAll();
160
4
161
4
    auto ret = test_command_mpd->execute(test_v,&test_my_data);
162
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::STOP);
163
4
    EXPECT_STREQ(ret.c_str(), "stoped!");
164
4
}
165
166
TEST_F(command_mpd_Class_fixture, play_playID)
167
4
{
168
4
    test_my_data.idom_all_state.houseState = STATE::UNLOCK;
169
4
    test_my_data.ptr_MPD_info->currentSongID = 2;
170
4
    test_my_data.ptr_MPD_info->songList = {"song 1","song 2","song 3"};
171
4
172
4
    test_v.clear();
173
4
    test_v.push_back("mpd");
174
4
    test_v.push_back("start");
175
4
176
4
    blockQueue test_q;
177
4
    test_q._clearAll();
178
4
179
4
    test_command_mpd->execute(test_v,&test_my_data);
180
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PLAY);
181
4
182
4
    test_v.clear();
183
4
    test_v.push_back("mpd");
184
4
    test_v.push_back("start");
185
4
    test_v.push_back("3");
186
4
187
4
    test_q._clearAll();
188
4
189
4
    test_command_mpd->execute(test_v,&test_my_data);
190
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PLAY_ID);
191
4
    EXPECT_EQ(test_my_data.ptr_MPD_info->currentSongID, 3);
192
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_ok_BT.cpp
Line
Count
Source
1
#include "../command_ok.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_ok_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_ok_Class_fixture()
8
4
    {
9
4
10
4
    }
11
12
protected:
13
    std::unique_ptr<command_ok> test_command_ok;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
4
    {
18
4
        iDomTOOLS_ClassTest::SetUp();
19
4
        test_command_ok =  std::make_unique <command_ok> ("ok");
20
4
    }
21
22
    void TearDown() final
23
4
    {
24
4
        iDomTOOLS_ClassTest::TearDown();
25
4
    }
26
};
27
28
TEST_F(command_ok_Class_fixture, main)
29
4
{
30
4
    test_v.push_back("ok");
31
4
    auto ret = test_command_ok->execute(test_v,&test_my_data);
32
4
    EXPECT_STREQ(ret.c_str(),"\nEND\n");
33
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_program_BT.cpp
Line
Count
Source
1
#include "../command_program.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_program_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_program_Class_fixture()
8
36
    {
9
36
10
36
    }
11
12
protected:
13
    std::unique_ptr<command_program> test_command_program;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
36
    {
18
36
        iDomTOOLS_ClassTest::SetUp();
19
36
        test_command_program = std::make_unique <command_program> ("program");
20
36
    }
21
22
    void TearDown() final
23
36
    {
24
36
        iDomTOOLS_ClassTest::TearDown();
25
36
    }
26
};
27
28
TEST_F(command_program_Class_fixture, unknownParameter)
29
4
{
30
4
    test_v.clear();
31
4
    test_v.push_back("program");
32
4
    test_v.push_back("test");
33
4
    auto ret = test_command_program->execute(test_v,&test_my_data);
34
4
    EXPECT_STREQ(ret.c_str(), "add more paramiters");
35
4
36
4
}
37
38
TEST_F(command_program_Class_fixture, missingParameter)
39
4
{
40
4
    test_v.clear();
41
4
    test_v.push_back("program");
42
4
    auto ret = test_command_program->execute(test_v,&test_my_data);
43
4
    EXPECT_THAT(ret, ::testing::HasSubstr("what?"));
44
4
}
45
46
TEST_F(command_program_Class_fixture, fakeParameter)
47
4
{
48
4
    test_v.clear();
49
4
    test_v.push_back("program");
50
4
    test_v.push_back("fake");
51
4
    test_v.push_back("fake2");
52
4
    auto ret = test_command_program->execute(test_v,&test_my_data);
53
4
    EXPECT_THAT(ret, ::testing::HasSubstr("what? - fake"));
54
4
}
55
56
TEST_F(command_program_Class_fixture, stopProgram)
57
4
{
58
4
    test_v.clear();
59
4
    test_v.push_back("program");
60
4
    test_v.push_back("stop");
61
4
    EXPECT_THROW(test_command_program->execute(test_v,&test_my_data), std::string);
62
4
}
63
64
TEST_F(command_program_Class_fixture, programReloadSoft)
65
4
{
66
4
    test_v.clear();
67
4
    test_v.push_back("program");
68
4
    test_v.push_back("reload");
69
4
    test_v.push_back("soft");
70
4
    EXPECT_THROW(test_command_program->execute(test_v,&test_my_data), std::string);
71
4
    EXPECT_EQ(test_my_data.iDomProgramState, iDomStateEnum::RELOAD);
72
4
}
73
74
TEST_F(command_program_Class_fixture, programReloadHard)
75
4
{
76
4
    test_v.clear();
77
4
    test_v.push_back("program");
78
4
    test_v.push_back("reload");
79
4
    test_v.push_back("hard");
80
4
    EXPECT_THROW(test_command_program->execute(test_v,&test_my_data), std::string);
81
4
    EXPECT_EQ(test_my_data.iDomProgramState, iDomStateEnum::HARD_RELOAD);
82
4
}
83
84
TEST_F(command_program_Class_fixture, clearRamProgram)
85
4
{
86
4
    test_v.clear();
87
4
    test_v.push_back("program");
88
4
    test_v.push_back("clear");
89
4
    test_v.push_back("ram");
90
4
    auto ret = test_command_program->execute(test_v,&test_my_data);
91
4
    EXPECT_STREQ(ret.c_str(),"ram has beed freed");
92
4
}
93
94
TEST_F(command_program_Class_fixture, raspberryProgram)
95
4
{
96
4
    test_v.clear();
97
4
    test_v.push_back("program");
98
4
    test_v.push_back("raspberry");
99
4
    test_v.push_back("command");
100
4
    auto ret = test_command_program->execute(test_v,&test_my_data);
101
4
    EXPECT_STREQ(ret.c_str(),"command done with exitcode: 0");
102
4
}
103
104
TEST_F(command_program_Class_fixture, debugeVariableProgram)
105
4
{
106
4
    RFLinkHandler test_RFLinkkHandler(&test_my_data);
107
4
108
4
    test_my_data.main_RFLink = &test_RFLinkkHandler;
109
4
    test_my_data.main_RFLink->okTime = 777;
110
4
    test_my_data.main_RFLink->pingTime = 888;
111
4
    test_my_data.server_settings->PORT = 88;
112
4
    test_my_data.server_settings->v_delay = 1;
113
4
    test_my_data.sleeper = 1;
114
4
    test_my_data.now_time = 123;
115
4
    test_my_data.start = 12;
116
4
    int32_t buf = 1;
117
4
    unsigned int who = 0;
118
4
    test_my_data.pointer.ptr_buf = &buf;
119
4
    test_my_data.pointer.ptr_who = &who;
120
4
121
4
    test_v.clear();
122
4
    test_v.push_back("program");
123
4
    test_v.push_back("debuge");
124
4
    test_v.push_back("variable");
125
4
    auto ret = test_command_program->execute(test_v,&test_my_data);
126
4
    std::cout << ret << std::endl;
127
4
    EXPECT_THAT(ret,testing::HasSubstr("END"));
128
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_put_BT.cpp
Line
Count
Source
1
#include "../command_put.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_put_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_put_Class_fixture()
8
4
    {
9
4
10
4
    }
11
12
protected:
13
    std::unique_ptr<command_put> test_command_put;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
4
    {
18
4
        iDomTOOLS_ClassTest::SetUp();
19
4
        test_command_put = std::make_unique <command_put> ("put");
20
4
    }
21
22
    void TearDown() final
23
4
    {
24
4
        iDomTOOLS_ClassTest::TearDown();
25
4
    }
26
};
27
28
TEST_F(command_put_Class_fixture, main)
29
4
{
30
4
    TEST_DATA::return_send_to_arduino = "-2:3";
31
4
32
4
    test_v.push_back("put");
33
4
    test_v.push_back("temperature");
34
4
    auto ret = test_command_put->execute(test_v,&test_my_data);
35
4
    EXPECT_STREQ(ret.c_str(), "DONE");
36
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_rs232_BT.cpp
Line
Count
Source
1
#include "../commandrs232.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_RS232_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_RS232_Class_fixture()
8
32
    {
9
32
10
32
    }
11
12
protected:
13
    std::unique_ptr<commandRS232> test_command_put;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
32
    {
18
32
        iDomTOOLS_ClassTest::SetUp();
19
32
        test_command_put = std::make_unique <commandRS232> ("RS232");
20
32
    }
21
22
    void TearDown() final
23
32
    {
24
32
        iDomTOOLS_ClassTest::TearDown();
25
32
    }
26
};
27
28
TEST_F(command_RS232_Class_fixture, wrongParameter)
29
4
{
30
4
    test_v.push_back("RS232");
31
4
    test_v.push_back("test_par");
32
4
    auto ret = test_command_put->execute(test_v,&test_my_data);
33
4
    EXPECT_STREQ(ret.c_str(), "wrong parameter: test_par");
34
4
}
35
36
TEST_F(command_RS232_Class_fixture, getWrongParameter)
37
4
{
38
4
    test_v.push_back("RS232");
39
4
    test_v.push_back("get");
40
4
    test_v.push_back("fake");
41
4
    auto ret = test_command_put->execute(test_v,&test_my_data);
42
4
    EXPECT_STREQ(ret.c_str(), "wrong parameter: fake");
43
4
}
44
45
TEST_F(command_RS232_Class_fixture, getTemperature)
46
4
{
47
4
    TEST_DATA::return_send_to_arduino = "-2:-21";
48
4
49
4
    test_v.push_back("RS232");
50
4
    test_v.push_back("get");
51
4
    test_v.push_back("temperature");
52
4
    auto ret = test_command_put->execute(test_v,&test_my_data);
53
4
    EXPECT_THAT(ret, ::testing::HasSubstr("-2:-21"));
54
4
}
55
56
TEST_F(command_RS232_Class_fixture, send)
57
4
{
58
4
    TEST_DATA::return_send_to_arduino = "done";
59
4
60
4
    test_v.push_back("RS232");
61
4
    test_v.push_back("send");
62
4
    test_v.push_back("test:33;");
63
4
    auto ret = test_command_put->execute(test_v,&test_my_data);
64
4
    EXPECT_STREQ(ret.c_str(), "done");
65
4
}
66
67
TEST_F(command_RS232_Class_fixture, errorMissingPara)
68
4
{
69
4
    TEST_DATA::return_send_to_arduino = "done";
70
4
71
4
    test_v.push_back("RS232");
72
4
    test_v.push_back("error");
73
4
    auto ret = test_command_put->execute(test_v,&test_my_data);
74
4
    EXPECT_STREQ(ret.c_str(), "add more parameter to error");
75
4
}
76
77
TEST_F(command_RS232_Class_fixture, errorTemperatureMissingPara)
78
4
{
79
4
    TEST_DATA::return_send_to_arduino = "done";
80
4
81
4
    test_v.push_back("RS232");
82
4
    test_v.push_back("error");
83
4
    test_v.push_back("Temperature");
84
4
    test_v.push_back("error");
85
4
    auto ret = test_command_put->execute(test_v,&test_my_data);
86
4
    EXPECT_STREQ(ret.c_str(), "default");
87
4
}
88
89
TEST_F(command_RS232_Class_fixture, msgTestMissing)
90
4
{
91
4
    TEST_DATA::return_send_to_arduino = "done";
92
4
93
4
    test_v.push_back("RS232");
94
4
    test_v.push_back("error");
95
4
    test_v.push_back("test");
96
4
    test_v.push_back("msg");
97
4
98
4
    test_v.push_back("fake msg");
99
4
100
4
    auto ret = test_command_put->execute(test_v,&test_my_data);
101
4
    EXPECT_STREQ(ret.c_str(), "DONE!");
102
4
}
103
104
TEST_F(command_RS232_Class_fixture, msgTestFake)
105
4
{
106
4
    TEST_DATA::return_send_to_arduino = "done";
107
4
108
4
    test_v.push_back("RS232");
109
4
    test_v.push_back("error");
110
4
    test_v.push_back("test");
111
4
    test_v.push_back("fake");;
112
4
113
4
    auto ret = test_command_put->execute(test_v,&test_my_data);
114
4
    EXPECT_STREQ(ret.c_str(), "default");
115
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_show_BT.cpp
Line
Count
Source
1
#include "../command_show.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_show_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_show_Class_fixture()
8
36
    {
9
36
10
36
    }
11
12
protected:
13
    std::unique_ptr<command_show> test_command_show;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
36
    {
18
36
        iDomTOOLS_ClassTest::SetUp();
19
36
        test_command_show = std::make_unique <command_show> ("show");
20
36
    }
21
22
    void TearDown() final
23
36
    {
24
36
        iDomTOOLS_ClassTest::TearDown();
25
36
    }
26
};
27
28
TEST_F(command_show_Class_fixture, wrongParameter)
29
4
{
30
4
    test_v.push_back("show");
31
4
    test_v.push_back("t");
32
4
    auto ret = test_command_show->execute(test_v,&test_my_data);
33
4
    EXPECT_STREQ(ret.c_str(), "wrong parameter: t");
34
4
}
35
36
TEST_F(command_show_Class_fixture, unknownParameter)
37
4
{
38
4
    test_v.push_back("show");
39
4
    auto ret = test_command_show->execute(test_v,&test_my_data);
40
4
    EXPECT_STREQ(ret.c_str(), "show what?");
41
4
}
42
43
TEST_F(command_show_Class_fixture, showThreadAll)
44
4
{
45
4
    std::array<Thread_array_struc, iDomConst::MAX_CONNECTION> threadArray;
46
4
47
4
    threadArray[1].thread_ID = std::this_thread::get_id();
48
4
    threadArray[1].thread_name = "thread1 test1";
49
4
    threadArray[1].thread_socket = 1;
50
4
    threadArray[2].thread_ID = std::this_thread::get_id();
51
4
    threadArray[2].thread_name = "thread1 test2";
52
4
    threadArray[2].thread_socket = 2;
53
4
54
4
    test_my_data.main_THREAD_arr = &threadArray;
55
4
56
4
    test_v.push_back("show");
57
4
    test_v.push_back("thread");
58
4
    test_v.push_back("all");
59
4
    auto ret = test_command_show->execute(test_v,&test_my_data);
60
4
    EXPECT_THAT(ret, testing::HasSubstr("socket: 2"));
61
4
}
62
63
TEST_F(command_show_Class_fixture, showThread)
64
4
{
65
4
    std::array<Thread_array_struc, iDomConst::MAX_CONNECTION> threadArray;
66
4
67
4
    threadArray[1].thread_ID = std::this_thread::get_id();
68
4
    threadArray[1].thread_name = "thread1 test1";
69
4
    threadArray[1].thread_socket = 1;
70
4
    threadArray[2].thread_ID = std::this_thread::get_id();
71
4
    threadArray[2].thread_name = "thread1 test2";
72
4
    threadArray[2].thread_socket = 2;
73
4
74
4
    test_my_data.main_THREAD_arr = &threadArray;
75
4
76
4
    test_v.push_back("show");
77
4
    test_v.push_back("thread");
78
4
    test_v.push_back("2");
79
4
    auto ret = test_command_show->execute(test_v,&test_my_data);
80
4
    EXPECT_THAT(ret, testing::HasSubstr("socket: 2"));
81
4
}
82
83
TEST_F(command_show_Class_fixture, showThreadNoId)
84
4
{
85
4
    test_v.push_back("show");
86
4
    test_v.push_back("thread");
87
4
    auto ret = test_command_show->execute(test_v,&test_my_data);
88
4
    EXPECT_STREQ(ret.c_str(), "No ID");
89
4
}
90
91
TEST_F(command_show_Class_fixture, showLog)
92
4
{
93
4
    test_v.push_back("show");
94
4
    test_v.push_back("log");
95
4
    auto ret = test_command_show->execute(test_v,&test_my_data);
96
4
    EXPECT_THAT(ret, testing::HasSubstr("VERBOSE"));
97
4
}
98
99
TEST_F(command_show_Class_fixture, showLogNoInfo)
100
4
{
101
4
    test_v.push_back("show");
102
4
    test_v.push_back("log");
103
4
    test_v.push_back("no");
104
4
    test_v.push_back("INFO");
105
4
    auto ret = test_command_show->execute(test_v,&test_my_data);
106
4
    EXPECT_THAT(ret, testing::HasSubstr("VERBOSE"));
107
4
    EXPECT_THAT(ret, testing::Not(testing::HasSubstr("INFO")));
108
4
}
109
110
TEST_F(command_show_Class_fixture, showLogInfo)
111
4
{
112
4
    test_v.push_back("show");
113
4
    test_v.push_back("log");
114
4
    test_v.push_back("INFO");
115
4
    auto ret = test_command_show->execute(test_v,&test_my_data);
116
4
    EXPECT_THAT(ret, testing::HasSubstr("INFO"));
117
4
}
118
119
TEST_F(command_show_Class_fixture, showLogFakeInfo)
120
4
{
121
4
    test_v.push_back("show");
122
4
    test_v.push_back("log");
123
4
    test_v.push_back("fake");
124
4
    test_v.push_back("INFO");
125
4
    auto ret = test_command_show->execute(test_v,&test_my_data);
126
4
    EXPECT_STREQ(ret.c_str(), "do you mean : show log no <string>?");
127
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_sleep_BT.cpp
Line
Count
Source
1
#include "../command_sleep.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_sleep_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_sleep_Class_fixture()
8
20
    {
9
20
10
20
    }
11
12
protected:
13
    std::unique_ptr<command_sleep> test_command_sleep;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
20
    {
18
20
        iDomTOOLS_ClassTest::SetUp();
19
20
        test_command_sleep = std::make_unique <command_sleep> ("sleep");
20
20
    }
21
22
    void TearDown() final
23
20
    {
24
20
        iDomTOOLS_ClassTest::TearDown();
25
20
    }
26
};
27
28
TEST_F(command_sleep_Class_fixture, sleep)
29
4
{
30
4
    test_my_data.sleeper = 88;
31
4
32
4
    test_v.push_back("sleep");
33
4
    auto ret = test_command_sleep->execute(test_v,&test_my_data);
34
4
    EXPECT_STREQ(ret.c_str(), "sleep set to: 88");
35
4
}
36
37
TEST_F(command_sleep_Class_fixture, sleepFakeParam)
38
4
{
39
4
    test_my_data.sleeper = 88;
40
4
41
4
    test_v.push_back("sleep");
42
4
    test_v.push_back("fake");
43
4
    auto ret = test_command_sleep->execute(test_v,&test_my_data);
44
4
    EXPECT_STREQ(ret.c_str(), "internal error");
45
4
}
46
47
TEST_F(command_sleep_Class_fixture, sleepFakeParam2)
48
4
{
49
4
    test_my_data.sleeper = 88;
50
4
51
4
    test_v.push_back("sleep");
52
4
    test_v.push_back("fake");
53
4
    test_v.push_back("fake2");
54
4
    auto ret = test_command_sleep->execute(test_v,&test_my_data);
55
4
    EXPECT_STREQ(ret.c_str(), "wrong parametr fake");
56
4
}
57
58
TEST_F(command_sleep_Class_fixture, sleepSetNoIntiger)
59
4
{
60
4
    test_my_data.sleeper = 88;
61
4
62
4
    test_v.push_back("sleep");
63
4
    test_v.push_back("set");
64
4
    test_v.push_back("fake2");
65
4
    auto ret = test_command_sleep->execute(test_v,&test_my_data);
66
4
    EXPECT_STREQ(ret.c_str(), "system need intiger > 0 not: fake2");
67
4
}
68
69
TEST_F(command_sleep_Class_fixture, sleepSet)
70
4
{
71
4
    std::array<Thread_array_struc, iDomConst::MAX_CONNECTION> threadArray;
72
4
73
4
    threadArray[1].thread_ID = std::this_thread::get_id();
74
4
    threadArray[1].thread_name = "thread1 test1";
75
4
    threadArray[1].thread_socket = 1;
76
4
    threadArray[2].thread_ID = std::this_thread::get_id();
77
4
    threadArray[2].thread_name = "thread1 test2";
78
4
    threadArray[2].thread_socket = 2;
79
4
80
4
    test_my_data.main_THREAD_arr = &threadArray;
81
4
82
4
    test_v.push_back("sleep");
83
4
    test_v.push_back("set");
84
4
    test_v.push_back("2");
85
4
    auto ret = test_command_sleep->execute(test_v,&test_my_data);
86
4
    EXPECT_STREQ(ret.c_str(), "DONE - Sleep MPD STARTED");
87
4
    sleep(1);
88
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_state_BT.cpp
Line
Count
Source
1
#include "../command_state.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_state_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_state_Class_fixture()
8
12
    {
9
12
10
12
    }
11
12
protected:
13
    std::unique_ptr<command_state> test_command_state;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
12
    {
18
12
        iDomTOOLS_ClassTest::SetUp();
19
12
        test_command_state = std::make_unique <command_state> ("state");
20
12
    }
21
22
    void TearDown() final
23
12
    {
24
12
        iDomTOOLS_ClassTest::TearDown();
25
12
    }
26
};
27
28
TEST_F(command_state_Class_fixture, stateAll)
29
4
{
30
4
    test_v.clear();
31
4
    test_v.push_back("state");
32
4
    test_v.push_back("all");
33
4
    auto ret = test_command_state->execute(test_v,&test_my_data);
34
4
    EXPECT_STREQ(ret.c_str(), "state: KODI=DEACTIVE alarm=DEACTIVE cameraLED=UNKNOWN house=UNDEFINE printer=OFF speakers=OFF ");
35
4
}
36
37
TEST_F(command_state_Class_fixture, stateGetOne)
38
4
{
39
4
    test_v.clear();
40
4
    test_v.push_back("state");
41
4
    test_v.push_back("KODI");
42
4
    auto ret = test_command_state->execute(test_v,&test_my_data);
43
4
    EXPECT_STREQ(ret.c_str(), "DEACTIVE");
44
4
}
45
46
TEST_F(command_state_Class_fixture, stateMissingParam)
47
4
{
48
4
    test_v.clear();
49
4
    test_v.push_back("state");
50
4
    auto ret = test_command_state->execute(test_v,&test_my_data);
51
4
    EXPECT_THAT(ret, testing::HasSubstr("need parameter!\n"));
52
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_test_BT.cpp
Line
Count
Source
1
#include "../commandtest.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_test_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_test_Class_fixture()
8
12
    {
9
12
10
12
    }
11
12
protected:
13
    std::unique_ptr<commandTEST> test_command_test;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
12
    {
18
12
        iDomTOOLS_ClassTest::SetUp();
19
12
        test_command_test = std::make_unique <commandTEST> ("test");
20
12
    }
21
22
    void TearDown() final
23
12
    {
24
12
        iDomTOOLS_ClassTest::TearDown();
25
12
    }
26
};
27
28
TEST_F(command_test_Class_fixture, test)
29
4
{
30
4
    test_v.push_back("test");
31
4
    test_v.push_back("test");
32
4
    auto ret = test_command_test->execute(test_v,&test_my_data);
33
4
    EXPECT_STREQ(ret.c_str(),"test - for test");
34
4
}
35
36
TEST_F(command_test_Class_fixture, throw)
37
4
{
38
4
    test_v.push_back("test");
39
4
    test_v.push_back("throw");
40
4
    EXPECT_THROW(test_command_test->execute(test_v,&test_my_data),std::string);
41
4
}
42
43
TEST_F(command_test_Class_fixture, unknownParam)
44
4
{
45
4
    test_v.push_back("test");
46
4
    test_v.push_back("fake");
47
4
    auto ret = test_command_test->execute(test_v,&test_my_data);
48
4
    EXPECT_EQ(ret.size(),49);
49
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/TEST/command_uptime_BT.cpp
Line
Count
Source
1
#include "../command_uptime.h"
2
#include "../../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_uptime_Class_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_uptime_Class_fixture()
8
4
    {
9
4
10
4
    }
11
12
protected:
13
    std::unique_ptr<command_UPTIME> test_command_uptime;
14
15
    std::vector<std::string> test_v;
16
    void SetUp() final
17
4
    {
18
4
        iDomTOOLS_ClassTest::SetUp();
19
4
        test_command_uptime = std::make_unique <command_UPTIME> ("uptime");
20
4
    }
21
22
    void TearDown() final
23
4
    {
24
4
        iDomTOOLS_ClassTest::TearDown();
25
4
    }
26
};
27
28
TEST_F(command_uptime_Class_fixture, main)
29
4
{
30
4
    time(&test_my_data.start);
31
4
    test_v.push_back("uptime");
32
4
    auto ret = test_command_uptime->execute(test_v,&test_my_data);
33
4
    std::cout << "DATA: " << ret << std::endl;
34
4
    EXPECT_STREQ(ret.c_str(),"uptime: \n0 day 0 hours 0 minutes 0 seconds");
35
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_433mhz.cpp
Line
Count
Source
1
#include "command_433mhz.h"
2
#include "../../RADIO_433_eq/radio_433_eq.h"
3
#include "../../433MHz/RFLink/rflinkhandler.h"
4
5
command_433MHz::command_433MHz(const std::string &name):command(name)
6
88
{
7
88
}
8
9
command_433MHz::~command_433MHz()
10
88
{
11
88
    // puts("command_433MHz::~command_433MHz()");
12
88
}
13
14
std::string command_433MHz::execute(std::vector<std::string> &v, thread_data *my_data)
15
172
{
16
172
    std::string str_buf = "wrong paramiter\n" + help();
17
172
    if (v.size() > 2){
18
172
        //////////////////////////// switch
19
172
        if (v[1] == "show" && v[2] == "all"){
20
88
            str_buf = my_data->main_REC->listAllName();
21
88
        }
22
84
        else if (v[1] == "delete" && v.size() == 3)
23
16
        {
24
16
            if (my_data->main_REC->nameExist(v[2]) == false)
25
4
            {
26
4
                return "equipment "+ v[2]+" not exist ";
27
4
            }
28
12
            my_data->main_REC->deleteRadioEq(v[2]);
29
12
            str_buf = v[2] + " deleted";
30
12
        }
31
68
        else if (v[1] == "add" && v.size() > 3) //zmień tu
32
28
        {
33
28
            RADIO_EQ_CONFIG cfg;
34
28
           /* if(v[2] == "SWITCH" && v.size() == 12)
35
28
                cfg.set(v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11]); // zmień tu
36
28
            else*/ if(v[2] == "BUTTON" && v.size() >= 6)
37
4
                cfg.set(v[2],v[3],v[4],v[5],v[6]); // zmień tu
38
24
            else if(v[2] == "WEATHER" && v.size() >= 4)
39
4
                cfg.set(v[2],v[3],v[4]); // zmień tu
40
20
            else
41
20
            {
42
20
                if (v.size() != 12)
43
4
                    return "mising paramiter!";
44
16
                cfg.set(v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11]); // zmień tu
45
16
                //return v[2] + " " + v[3] + " " + v[4] + "add more paramiter or wrong type";
46
16
}
47
28
            /////////////////////////////////////////////////////////////
48
28
            if (my_data->main_REC->nameExist(v[3]) == true)
49
4
            {
50
4
                return "equipment "+ v[3]+" exist ";
51
4
            }
52
20
            try
53
20
            {
54
20
                my_data->main_REC->addRadioEq(cfg,v[2]);
55
20
            }
56
20
            catch(const WRONG_FORMAT& )
57
20
            {
58
4
                return "wrong type "+v[2];
59
4
            }
60
4
            catch(const std::invalid_argument& )
61
4
            {
62
4
                return "wrong ID "+v[4];
63
4
            }
64
12
65
12
            str_buf = v[2] + " " + v[3] + " added";
66
12
            my_data->main_REC->saveConfig(my_data->server_settings->radio433MHzConfigFile);
67
12
        }
68
40
        else if (v[1] == "show" && v[2] == "switch"){
69
4
            str_buf = "";
70
4
            for (auto m_switch : my_data->main_REC->getSwitchPointerVector())
71
20
            {
72
20
                str_buf.append(stateToString(m_switch->getState()) );
73
20
            }
74
4
        }
75
36
        else if (v[1] == "show" && v[2] == "aether"){
76
4
            str_buf.clear();
77
4
            for(auto itr = my_data->main_RFLink->rflinkMAP.begin();
78
12
                itr != my_data->main_RFLink->rflinkMAP.end();
79
8
                itr++)
80
8
            {
81
8
                str_buf += itr->second.read();
82
8
                str_buf += '\n';
83
8
            }
84
4
            str_buf += ".";
85
4
86
4
        }
87
32
        else if (v[1] == "show" && v[2] == "config"){
88
4
            str_buf = my_data->main_REC->showConfig(my_data->server_settings->radio433MHzConfigFile);
89
4
        }
90
28
        else if (v[1] == "send"){
91
4
            str_buf = "sended!;";
92
4
            my_data->main_RFLink->sendCommand(v[2]);
93
4
94
4
        }
95
24
        else if (v[1] == "switch"){
96
24
            try{
97
24
                RADIO_SWITCH *m_switch = dynamic_cast<RADIO_SWITCH*>(my_data->main_REC->getEqPointer(v[2]));
98
24
99
24
                if (v[3] == "ON") {
100
4
                    m_switch->on();
101
4
                    str_buf = " done ";
102
4
                }
103
20
                else if (v[3] == "OFF"){
104
4
                    m_switch->off();
105
4
                    str_buf = " done ";
106
4
                }
107
16
                else if (v[3] == "15s"){
108
4
                    m_switch->onFor15sec();
109
4
                    str_buf = " done ";
110
4
                }
111
12
                else{
112
12
                    str_buf = "unknown paramiter: ";
113
12
                    str_buf.append(v[3]);
114
12
                }
115
24
            }
116
24
            catch (std::string& error){
117
8
                str_buf = error;
118
8
            }
119
24
            my_data->main_iDomTools->saveState_iDom();
120
24
        }
121
172
        /////////////////////////////////////////////
122
172
    }
123
172
    return str_buf;
124
172
}
125
126
std::string command_433MHz::help()
127
176
{
128
176
    std::stringstream help;
129
176
    help << ("433MHz delete <name> - dalete radio equipment") <<std::endl;
130
176
    help << ("433MHz add <type> <name> <ID> <onCode> <offCode> <on15sec> <sunrise> <sunset> <lock> <unlock> - add radio equipment") <<std::endl;
131
176
    help << ("433MHz switch <name> ON/OFF/15s - change switch state") <<std::endl;
132
176
    help << ("433MHz show all - list all equipment by name") <<std::endl;
133
176
    help << ("433MHz show aether - show aether devices by ID") <<std::endl;
134
176
    help << ("433MHz show config - show 433MHz devices config") <<std::endl;
135
176
    help << ("433MHz send <msg> - send command") <<std::endl;
136
176
    return help.str();
137
176
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_ardu.cpp
Line
Count
Source
1
#include "command_ardu.h"
2
3
command_ardu::command_ardu(const std::string &name):command(name)
4
4
{
5
4
    this->m_mainRadioButton = std::nullptr_t();
6
4
}
7
8
command_ardu::command_ardu(const std::string& name, thread_data *my_data):command(name)
9
  ,m_button433MHzVector(my_data->main_REC->getButtonPointerVector())
10
72
{
11
72
    //m_button433MHzVector = my_data->main_REC->getButtonPointerVector();
12
72
    m_mainRadioButton = static_cast<RADIO_BUTTON*>(my_data->main_REC->getEqPointer("locker"));
13
72
14
72
    m_weatherStVe = my_data->main_REC->getWeather_StationPtrVector();
15
72
    m_mainWeatherStation = static_cast<RADIO_WEATHER_STATION*>(my_data->main_REC->getEqPointer("first"));
16
72
}
17
18
std::string command_ardu::execute(std::vector<std::string> &v, thread_data *my_data)
19
56
{
20
56
    std::string str_buf = " only for internal usage!";
21
56
    if (v.size() > 1){
22
56
        if(v[1] == "show"){
23
4
            RADIO_WEATHER_STATION* st = static_cast<RADIO_WEATHER_STATION*>(my_data->main_REC->getEqPointer("first"));
24
4
            str_buf = st->data.getDataString();
25
4
        }
26
56
        if(v[1] == "433MHz"){
27
52
            my_data->myEventHandler.run("433MHz")->addEvent("RFLink: "+v[2]);
28
52
            try {
29
52
                my_data->main_RFLink->
30
52
                        rflinkMAP[my_data->main_RFLink->getArgumentValueFromRFLinkMSG(v[2],
31
52
                        "ID")].counter();
32
52
                my_data->main_RFLink->
33
52
                        rflinkMAP[my_data->main_RFLink->getArgumentValueFromRFLinkMSG(v[2],
34
52
                        "ID")].msg = v[2];
35
52
            }
36
52
            catch(const std::string& e){
37
12
                std::cout << "wyjatek w szukaniu: " << e <<std::endl;
38
12
                pingAndOkRecv( my_data, v[2]);
39
12
            }
40
52
            //TODO add command
41
52
            try {
42
48
                if (m_mainRadioButton->getID() == my_data->main_RFLink->getArgumentValueFromRFLinkMSG(v[2],"ID") )
43
24
                {
44
24
                    my_data->main_iDomTools->button433mhzLockerPressed(m_mainRadioButton);
45
24
                }
46
48
            }
47
48
            catch (const std::string& e){ }
48
48
            try {
49
48
                if (m_mainWeatherStation->getID() == my_data->main_RFLink->getArgumentValueFromRFLinkMSG(v[2],"ID") )
50
12
                {
51
12
                    m_mainWeatherStation->data.putData(v[2]);
52
12
                }
53
48
            }
54
48
            catch (std::string& e){ }
55
48
        }
56
56
    }
57
56
    return str_buf;
58
56
}
59
60
std::string command_ardu::help()
61
8
{
62
8
    return " only for internal usege\n";
63
8
}
64
65
void command_ardu::pingAndOkRecv(thread_data *my_data, const std::string& s)
66
12
{
67
12
    if (s.find("OK;") != std::string::npos)
68
4
        my_data->main_RFLink->okTime = Clock::getUnixTime();
69
8
    else if (s.find("PONG;") != std::string::npos)
70
4
        my_data->main_RFLink->pingTime = Clock::getUnixTime();
71
12
    std::cout << "poing && ok recv " << s <<std::endl
72
12
              << " ok time: "<<my_data->main_RFLink->okTime<< std::endl
73
12
              << " ping time: "<<my_data->main_RFLink->pingTime<< std::endl;
74
12
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_big.cpp
Line
Count
Source
1
#include "command_big.h"
2
3
command_big::command_big(const std::string &name):command(name)
4
32
{
5
32
6
32
}
7
8
std::string command_big::execute(std::vector<std::string> &v, thread_data *my_data)
9
4
{
10
4
    std::string str_buf = "command big - wrong paramiter:\n "+ help();
11
4
    if (v.size() > 1){
12
4
        str_buf.erase();
13
220
        for (int i =0; i < std::stoi(v[1])-1; ++i){
14
216
            str_buf += "z";
15
216
        }
16
4
        str_buf += "Y";
17
4
    }
18
4
    return str_buf;
19
4
}
20
21
std::string command_big::help()
22
8
{
23
8
    return "big <number> - send big (number) data \n";
24
8
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_clock.cpp
Line
Count
Source
1
#include "command_clock.h"
2
#include "../../../src/functions/functions.h"
3
4
command_clock::command_clock(const std::string &name):command(name)
5
36
{
6
36
7
36
}
8
9
std::string command_clock::execute(std::vector<std::string> &v, thread_data *my_data)
10
8
{
11
8
    if (v.size() > 1){
12
4
        return "clock set "+ useful_F::send_to_arduino_clock(my_data,v[1]);
13
4
    }
14
4
    return "can not set clock";
15
4
}
16
17
std::string command_clock::help()
18
4
{
19
4
    return "clock <number/string> - put number/string (max 4 digits) to 7segment LCD\n";
20
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_cmd.cpp
Line
Count
Source
1
#include "command_cmd.h"
2
#include "../../../src/functions/functions.h"
3
4
command_cmd::command_cmd(const std::string &name):command(name)
5
36
{
6
36
7
36
}
8
9
std::string command_cmd::execute(std::vector<std::string> &v, thread_data *my_data)
10
8
{
11
8
    if (v.size() == 1){
12
4
        return "fifo file contain: "+ useful_F_libs::read_from_mkfifo(my_data->server_settings->omxplayerFile);
13
4
    }
14
4
    return "error: unknown parameter: "+v[1];
15
4
}
16
17
std::string command_cmd::help()
18
4
{
19
4
    return "cmd - read char prom cmd fifo file for unblock video player\n";
20
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_event.cpp
Line
Count
Source
1
#include "command_event.h"
2
3
command_event::command_event(const std::string &name) :command(name)
4
52
{
5
52
6
52
}
7
8
std::string command_event::execute(std::vector<std::string> &v, thread_data *my_data)
9
24
{
10
24
    if (v.size() == 1){
11
4
        return my_data->myEventHandler.getListPossibleEvents();
12
4
    }
13
20
    if (v.size() == 2){
14
4
        return my_data->myEventHandler.run(v[1])->getEvent();
15
4
    }
16
16
    if (v.size() == 3 && v[2]=="clear"){
17
4
        my_data->myEventHandler.run(v[1])->clearEvent();
18
4
        return "event " +v[1]+ " has been cleared!";
19
4
    }
20
12
    if (v.size() == 3 && v[2]=="intensity"){
21
4
        std::stringstream intensity;
22
4
        intensity << my_data->myEventHandler.run(v[1])->getLast1minNumberEvent();
23
4
        return "event " +v[1]+" "+ intensity.str() +" intensity per last minute!";
24
4
    }
25
8
    if (v.size() == 5 && v[2]=="clear"){
26
4
        unsigned int from = std::stoi(v[3]);
27
4
        unsigned int to = std::stoi(v[4]);
28
4
        my_data->myEventHandler.run(v[1])->clearEvent(from, to);
29
4
        return "event " +v[1]+ " has been cleared!";
30
4
    }
31
4
    return my_data->myEventHandler.help();
32
4
}
33
34
std::string command_event::help()
35
4
{
36
4
    std::stringstream help;
37
4
    help << "event- show actual event (all)" << std::endl;
38
4
    help << "event <name> - show one event" << std::endl;
39
4
    help << "event <name> clear - clear event <name>" << std::endl;
40
4
    help << "event <name> intensity - intensity per minute" <<std::endl;
41
4
    return help.str();
42
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_hello.cpp
Line
Count
Source
1
#include "command_hello.h"
2
3
command_hello::command_hello(const std::string &name):command(name)
4
32
{
5
32
}
6
7
command_hello::~command_hello()
8
32
{
9
32
}
10
11
std::string command_hello::execute(std::vector<std::string> &v, thread_data *my_data)
12
4
{
13
4
    return "\nHI You User!\n";
14
4
}
15
16
std::string command_hello::help()
17
4
{
18
4
    return "hello - send test message to server if connection is ok, the server response: \"HI!\"\n";
19
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_help.cpp
Line
Count
Source
1
#include "command_help.h"
2
#include <vector>
3
#include <algorithm>
4
5
command_help::command_help(const std::string &name):command(name)
6
40
{
7
40
}
8
9
std::string command_help::execute(std::vector<std::string> &v, thread_data *my_data)
10
12
{
11
12
    std::string result ="";
12
12
    if (v.size() ==2){
13
8
14
8
        if (my_data->commandMapPtr->find(v[1]) == my_data->commandMapPtr->end()){
15
4
            return "unknown command: "+ v[1]+" help note not found";
16
4
        }
17
4
        else{
18
4
            return my_data->commandMapPtr->find(v[1])->second->help();
19
4
        }
20
4
    }
21
4
    else
22
4
    {
23
92
        for( auto iter= my_data->commandMapPtr->begin();iter != my_data->commandMapPtr->end(); ++iter ) {
24
88
25
88
            result+= iter->second->help();
26
88
            result+= "------------------------------------\n";
27
88
        }
28
4
    }
29
12
    return result;
30
12
}
31
32
std::string command_help::help()
33
4
{
34
4
    return "help - show help for all command \nhelp <parameter> - show help for command\n";
35
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_idom.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "command_idom.h"
2
#include "../../functions/functions.h"
3
4
command_iDom::command_iDom(const std::string &name):command(name)
5
108
{
6
108
}
7
8
std::string command_iDom::execute(std::vector<std::string> &v, thread_data *my_data)
9
120
{
10
120
    if (v.size()<2){
11
4
        return "need parameter!\n" + help();
12
4
    }
13
116
    if (v[1]=="speakers")
14
12
    {
15
12
        if (v[2] =="ON"){
16
4
            iDomTOOLS::turnOnSpeakers();
17
4
            return "speakers ON";
18
4
        }
19
8
        else if (v[2]=="OFF"){
20
4
            iDomTOOLS::turnOffSpeakers();
21
4
            return "speakers OFF";
22
4
        }
23
4
        else{
24
4
            return "unknow speakers action: "+v[2];
25
4
        }
26
104
    }
27
104
    else if (v[1]=="sunset"){
28
4
        return my_data->main_iDomTools->getSunset(true);
29
4
    }
30
100
    else if (v[1]=="sunrise"){
31
4
        return my_data->main_iDomTools->getSunrise(true);
32
4
    }
33
96
    else if (v[1]=="day" && v[2]=="lenght"){
34
4
        return my_data->main_iDomTools->getDayLenght(true);
35
4
    }
36
92
    else if (v[1]=="sun"){
37
4
        std::string ret;
38
4
        ret = my_data->main_iDomTools->getSunrise(true);
39
4
        ret.append("\n");
40
4
        ret.append(my_data->main_iDomTools->getSunset(true));
41
4
        ret.append("\n");
42
4
        ret.append(my_data->main_iDomTools->getDayLenght(true));
43
4
        ret.append("\n");
44
4
        return ret;
45
4
    }
46
88
    else if (v[1]=="sysinfo"){
47
4
        return my_data->main_iDomTools->getSystemInfo();
48
4
    }
49
84
    else if (v[1]=="temperature"){
50
8
        if ( v.size() < 3){
51
4
            return my_data->main_iDomTools->getTemperatureString();
52
4
        }
53
4
        else {
54
4
            if (v[2] == "stats"){
55
4
                std::string ret;
56
4
                try{
57
4
                 ret = my_data->main_iDomTools->getThermoStats(v[3]);
58
4
                }
59
4
                catch (std::string& obj){
60
4
                    ret = obj +" "+v[3];
61
4
                }
62
4
               return ret;
63
76
            }
64
4
        }
65
76
    }
66
76
    else if (v[1]=="text"){
67
4
        return my_data->main_iDomTools->getTextToSpeach();
68
4
    }
69
72
    else if (v[1] == "lock"){
70
4
        my_data->main_iDomTools->lockHome();
71
4
        return "hous locked";
72
4
    }
73
68
    else if (v[1] == "unlock"){
74
4
        my_data->main_iDomTools->unlockHome();
75
4
        return "hous unlocked";
76
4
    }
77
64
    else if (v[1]=="LED"){
78
8
        if (v.size() != 7){
79
8
            if (v[2]=="OFF"){
80
4
                return my_data->main_iDomTools->ledOFF();
81
4
            }
82
4
            else if(v[2] == "set"){
83
0
               return my_data->main_iDomTools->ledOn(
84
0
                            my_data->ptr_pilot_led->colorLED[2],
85
0
                            std::stoi(v[3]),
86
0
                            std::stoi(v[4])
87
0
                            );
88
0
            }
89
4
            else{
90
4
                return "need more parameter from-to-R-G-B";
91
4
            }
92
0
        }
93
0
        else {
94
0
            LED_Strip strip(v[2],v[3],v[4],v[5],v[6]);
95
0
            return my_data->main_iDomTools->ledOn(strip);
96
0
        }
97
56
    }
98
56
    else if (v[1]=="say"){
99
4
        if (v.size() > 3){
100
4
            std::vector<std::string> vTTS ={ my_data->main_iDomTools->getTextToSpeach()};
101
4
            my_data->main_iDomTools->textToSpeach(&vTTS);
102
4
            return "sad";
103
4
        }
104
52
    }
105
52
    else if (v[1]=="smog"){
106
4
        return my_data->main_iDomTools->getSmog()+" mg/m^3";
107
4
    }
108
48
    else if (v[1]=="230V"){
109
12
        if (v.size() > 2 && v[2]=="ON"){
110
4
            my_data->main_iDomTools->turnOnPrinter();
111
4
            return "230V ON";
112
4
        }
113
8
        else if(v.size() > 2 && v[2]=="OFF"){
114
4
            my_data->main_iDomTools->turnOffPrinter();
115
4
            return "230V OFF";
116
4
        }
117
4
        else {
118
4
            return "wrong paramiter";
119
4
        }
120
36
    }
121
36
    else if (v[1]=="wifi"){
122
4
        std::string readBuffer = useful_F_libs::httpPost("http://cyniu88.no-ip.pl/cgi-bin/kto_wifi.sh",10);
123
4
        return readBuffer;
124
4
    }
125
32
    else if (v[1]=="lightning"){
126
4
        std::stringstream readBuffer;
127
4
        readBuffer << my_data->main_iDomTools->getLightningStruct().data.str();
128
4
        readBuffer << std::endl;
129
4
        readBuffer << "bool: " << my_data->main_iDomTools->getLightningStruct().riseAlarm;
130
4
        readBuffer <<std::endl <<" time: ";
131
4
        readBuffer << Clock::getTime().getString();
132
4
        return readBuffer.str();
133
4
    }
134
28
    else if (v[1]=="kill"){
135
0
136
0
        if (v[2]=="thread"){
137
0
            my_data->main_THREAD_arr->at(std::stoi(v[3]) ).thread.~thread();
138
0
            return "done!";
139
0
        }
140
28
    }
141
28
    else if (v[1]=="facebook"){
142
0
        std::string msg;
143
0
        for (unsigned int i = 2; i < v.size(); ++i){
144
0
            msg+=" ";
145
0
            msg+=v[i];
146
0
        }
147
0
        return my_data->main_iDomTools->postOnFacebook(msg);
148
0
    }
149
28
    else if (v[1]=="viber"){
150
0
        std::string msg;
151
0
        for (unsigned int i = 2; i < v.size(); ++i){
152
0
            msg+=" ";
153
0
            msg+=v[i];
154
0
        }
155
0
        STATE stMSG = my_data->main_iDomTools->sendViberMsgBool(msg, my_data->server_settings->viberReceiver.at(0),
156
0
                                                     my_data->server_settings->viberSender);
157
0
        if(stMSG == STATE::SEND_OK){
158
0
            return "wiadomosc wyslana poprawnie";
159
0
        }
160
0
        else{
161
0
            return "blad wysylania wiadomosci - sprawdz logi";
162
0
        }
163
28
    }
164
28
    else if (v[1] == "camera"){
165
12
166
12
        if (v.size() < 4){
167
4
            return "not enough parameters";
168
4
        }
169
8
        if (v[2]=="LED" && v[3] == "ON"){
170
4
            my_data->main_iDomTools->cameraLedON(my_data->server_settings->cameraLedON);
171
4
        }
172
4
        else if (v[2]=="LED" && v[3] == "OFF"){
173
4
            my_data->main_iDomTools->cameraLedOFF(my_data->server_settings->cameraLedOFF);
174
4
        }
175
8
        return "led DONE";
176
8
    }
177
16
    else if (v[1]=="weather"){
178
0
179
0
        if (v.size() < 4){
180
0
            return "not enough parameters";
181
0
        }
182
0
        std::string tempHTML = my_data->main_iDomTools->getWeatherEvent(v[2],std::stoi(v[3]));
183
0
        return useful_F_libs::removeHtmlTag(tempHTML);
184
0
    }
185
16
    else if (v[1] == "KODI"){
186
12
        return my_data->main_iDomTools->startKodi_Thread();
187
12
    }
188
4
    else if (v[1]=="alarm"){
189
0
190
0
        if (v.size() < 3){
191
0
            return "not enough parameters";
192
0
        }
193
0
        if (v[2] == "OFF"){
194
0
            my_data->alarmTime.state = STATE::DEACTIVE;
195
0
            my_data->main_iDomStatus->setObjectState("alarm", my_data->alarmTime.state);
196
0
            my_data->main_iDomTools->saveState_iDom();
197
0
            return "alarm clock has been deactivated";
198
0
        }
199
0
        else if (v[2] == "GET"){
200
0
            return my_data->alarmTime.time.getString();
201
0
        }
202
0
        else if (v[2] == "SET" && v.size() == 5){
203
0
            if (v[3] == "from")
204
0
            {
205
0
                my_data->alarmTime.fromVolume = std::stoi(v[4]);
206
0
            }
207
0
            else if (v[3] == "to")
208
0
            {
209
0
                my_data->alarmTime.toVolume = std::stoi(v[4]);
210
0
            }
211
0
            else if (v[3] == "radio")
212
0
            {
213
0
                my_data->alarmTime.radioID = std::stoi(v[4]);
214
0
            }
215
0
            std::stringstream ret;
216
0
            ret << "The values has beedn set:" << std::endl;
217
0
            ret << "From Value: " << my_data->alarmTime.fromVolume << std::endl;
218
0
            ret << "To Value: " << my_data->alarmTime.toVolume << std::endl;
219
0
            ret << "Radio ID: " << my_data->alarmTime.radioID << std::endl;
220
0
            my_data->main_iDomTools->saveState_iDom();
221
0
            return ret.str();
222
0
        }
223
0
        else if (v[2] == "ON" && v.size() > 3){
224
0
            my_data->alarmTime.time = Clock(v[3]);
225
0
            my_data->alarmTime.state = STATE::ACTIVE;
226
0
            my_data->main_iDomStatus->setObjectState("alarm", my_data->alarmTime.state);
227
0
            my_data->main_iDomTools->saveState_iDom();
228
0
            return "alarm clock has been activated";
229
0
        }
230
4
    }
231
4
    return "iDom - unknown parameter: "+ v[1];
232
4
}
233
234
std::string command_iDom::help()
235
12
{
236
12
    std::stringstream help;
237
12
    help << "iDom - for control smart home" << std::endl;
238
12
    help << "iDom speakers ON/OFF - to on or off speakers" << std::endl;
239
12
    help << "iDom 230v ON/OFF     - to on or off printers" << std::endl;
240
12
    help << "iDom sunset/sunrise/day lenght - to show those parameters" << std::endl;
241
12
    help << "iDom sun        - get sunrise, sunset and day lenght" << std::endl;
242
12
    help << "iDom sysinfo    - get system info" << std::endl;
243
12
    help << "iDom text       - get text to speach" << std::endl;
244
12
    help << "iDom say <text> - say standatrd info or <text>" << std::endl;
245
12
    help << "iDom sms <text> - send sms<text>" << std::endl;
246
12
    help << "iDom LED <FROM> <TO> <R> <G> <B> - set RGB LED strip" << std::endl;
247
12
    help << "iDom LED OFF    - led off" << std::endl;
248
12
    help << "iDom LED set <from> <to> - set green led from to" << std::endl;
249
12
    help << "iDom temperature - get temperature from all termomether" << std::endl;
250
12
    help << "iDom temperature stats <name> - get temperature stats from termomether <name>" << std::endl;
251
12
    help << "iDom smog       - get current SMOG level (KRAKOW)" << std::endl;
252
12
    help << "iDom kill thread <ID>  - kill thread but denger!" << std::endl;
253
12
    help << "iDom camera LED ON/OFF - LED camera work" << std::endl;
254
12
    help << "iDom facebook ... - post on facebook wall" << std::endl;
255
12
    help << "iDom viber ...   - send viber msg" << std::endl;
256
12
    help << "iDom weather <city> <radius> - get weather alert" << std::endl;
257
12
    help << "iDom lightning  - get lightning alert" << std::endl;
258
12
    help << "iDom alarm ON/OFF hh:mm - set larm clock" << std::endl;
259
12
    help << "iDom alarm SET from/to/radio <value> - set larm clock" << std::endl;
260
12
    help << "iDom alarm GET - get alarm time" << std::endl;
261
12
    help << "iDom lock   - lock home" << std::endl;
262
12
    help << "iDom unlock - unlock home" << std::endl;
263
12
    help << "iDom KODI - start KODI smart TV" << std::endl;
264
12
    help << "iDom wifi - show all wifi client" << std::endl;
265
12
    return help.str();
266
12
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_ip.cpp
Line
Count
Source
1
#include "command_ip.h"
2
3
command_ip::command_ip(const std::string &name):command(name)
4
32
{
5
32
}
6
7
std::string command_ip::execute(std::vector<std::string> &v, thread_data *my_data)
8
4
{
9
4
    return "iDom server IP: " +my_data->server_settings->SERVER_IP;
10
4
}
11
12
std::string command_ip::help()
13
4
{
14
4
    return "ip - show server IP address\n";
15
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_log.cpp
Line
Count
Source
1
#include "command_log.h"
2
3
command_log::command_log(const std::string &name):command(name)
4
32
{
5
32
}
6
7
std::string command_log::execute(std::vector<std::string> &v, thread_data *my_data)
8
32
{
9
32
    std::string msg;
10
64
    for (unsigned int i = 2; i < v.size(); ++i)
11
32
    {
12
32
        msg+=" ";
13
32
        msg+=v[i];
14
32
    }
15
32
    log_file_mutex.mutex_lock();
16
32
    log_file_cout <<"USER:- " << logLevel(v[1]) << msg <<std::endl;;
17
32
    log_file_mutex.mutex_unlock();
18
32
    return "DONE!";
19
32
}
20
21
std::string command_log::help()
22
4
{
23
4
    std::stringstream help;
24
4
    help << "log <logLevel> \"***TXT***\"- add *** to iDom logfile" << std::endl;
25
4
    return help.str();
26
4
}
27
28
logger_level command_log::logLevel(const std::string &level)
29
32
{
30
32
    if (level == "VERBOSE"){
31
4
        return VERBOSE;
32
4
    }
33
28
    else if (level == "DEBUG"){
34
4
        return DEBUG;
35
4
    }
36
24
    else if (level == "INFO"){
37
4
        return INFO;
38
4
    }
39
20
    else if (level == "WARNING"){
40
4
        return WARNING;
41
4
    }
42
16
    else if (level == "ERROR"){
43
4
        return ERROR;
44
4
    }
45
12
    else if (level == "FATAL"){
46
4
        return FATAL;
47
4
    }
48
8
    else if (level == "CRITICAL"){
49
4
        return CRITICAL;
50
4
    }
51
4
puts ("nie mam co wysetlic wale verbose");
52
4
        return VERBOSE;
53
4
54
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_mpd.cpp
Line
Count
Source
1
#include "command_mpd.h"
2
#include "../../blockQueue/blockqueue.h"
3
#include "../../functions/functions.h"
4
5
command_mpd::command_mpd(const std::string &name) :command(name)
6
64
{
7
64
}
8
9
std::string command_mpd::execute(std::vector<std::string> &v, thread_data *my_data)
10
56
{
11
56
    std::string str_buf;
12
56
13
56
    if (v[1]=="start")
14
8
    {
15
8
        if (v.size()>2)
16
4
        {
17
4
            int id = std::stoi(v[2]);
18
4
            if (id > 0)
19
4
            {
20
4
                iDomTOOLS::MPD_play(my_data,id);
21
4
                useful_F::sleep(1);
22
4
                str_buf = my_data->ptr_MPD_info->songList[id-1];
23
4
            }
24
4
        }
25
4
        else
26
4
        {
27
4
            iDomTOOLS::MPD_play(my_data);
28
4
            useful_F::sleep(1);
29
4
            str_buf=my_data->ptr_MPD_info->title;
30
4
        }
31
8
        my_data->main_iDomTools->saveState_iDom();
32
8
    }
33
48
    else if (v[1]=="stop")
34
4
    {
35
4
        iDomTOOLS::MPD_stop();
36
4
        str_buf="stoped!";
37
4
        my_data->main_iDomTools->saveState_iDom();
38
4
    }
39
44
    else if (v[1]=="next")
40
4
    {
41
4
        iDomTOOLS::MPD_next();
42
4
        useful_F::sleep(1);
43
4
        str_buf = my_data->ptr_MPD_info->radio + " : "+ my_data->ptr_MPD_info->title;
44
4
    }
45
40
    else if (v[1]=="prev")
46
4
    {
47
4
        iDomTOOLS::MPD_prev();
48
4
        useful_F::sleep(1);
49
4
        str_buf=my_data->ptr_MPD_info->radio+ " : "+ my_data->ptr_MPD_info->title;
50
4
    }
51
36
    else if (v[1]=="pause")
52
4
    {
53
4
        iDomTOOLS::MPD_pause();
54
4
        str_buf="paused!";
55
4
    }
56
32
    else if (v[1]=="volume")
57
16
    {
58
16
        if (v[2]=="up")
59
4
        {
60
4
            iDomTOOLS::MPD_volumeUp();
61
4
        }
62
12
        else if (v[2]=="down")
63
4
        {
64
4
            iDomTOOLS::MPD_volumeDown();
65
4
        }
66
8
        else
67
8
        {
68
8
            int vol = std::stoi(v[2]);
69
8
            if (vol >0 && vol <100)
70
4
            {
71
4
                iDomTOOLS::MPD_volumeSet(my_data,vol);
72
4
            }
73
8
        }
74
16
        //sleep(1);
75
16
        str_buf=std::to_string(my_data->ptr_MPD_info->volume);
76
16
    }
77
16
    else if (v[1]=="get")
78
8
    {
79
8
        if(v[2]=="volume")
80
4
        {
81
4
            str_buf=std::to_string(my_data->ptr_MPD_info->volume);
82
4
        }
83
4
        else if (v[2]=="info")
84
4
        {
85
4
            str_buf = my_data->ptr_MPD_info->radio + " : "+ my_data->ptr_MPD_info->title;
86
4
        }
87
8
    }
88
8
    else if (v[1]=="list")
89
4
    {
90
4
        for (auto i : my_data->ptr_MPD_info->songList)
91
12
            str_buf += i+"\n";
92
4
    }
93
4
    else
94
4
    {
95
4
        str_buf = "unknown parameter " + v[1];
96
4
    }
97
56
    return str_buf;
98
56
}
99
100
std::string command_mpd::help()
101
4
{
102
4
    std::stringstream help;
103
4
    help << "MPD - for control music player:" << std::endl;
104
4
    help << "parameter:" << std::endl;
105
4
    help << "\tstart - play music" << std::endl;
106
4
    help << "\tstop  - stop music" << std::endl;
107
4
    help << "\tpause - pause music" << std::endl;
108
4
    help << "\tnext  - next song" << std::endl;
109
4
    help << "\tprev  - previous song" << std::endl;
110
4
    help << "\tlist  - show playlist" << std::endl;
111
4
    help << "\tget volume - get volume %" << std::endl;
112
4
    help << "\tget info - get info about current song" << std::endl;
113
4
    help << "\tvolume up/down - increase/decrease volume 1%" << std::endl;
114
4
    return help.str();
115
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_ok.cpp
Line
Count
Source
1
#include "command_ok.h"
2
3
command_ok::command_ok(const std::string &name):command(name)
4
32
{
5
32
}
6
7
std::string command_ok::execute(std::vector<std::string> &v, thread_data *my_data)
8
8
{
9
8
    return "\nEND\n";
10
8
}
11
12
std::string command_ok::help()
13
8
{
14
8
    return "ok - confirmation msg server response: END \n";
15
8
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_program.cpp
Line
Count
Source
1
#include "command_program.h"
2
#include "../../functions/functions.h"
3
#include "../../433MHz/RFLink/rflinkhandler.h"
4
5
command_program::command_program(const std::string &name):command(name)
6
64
{
7
64
}
8
9
std::string command_program::execute(std::vector<std::string> &v, thread_data *my_data)
10
40
{
11
40
    std::string ret = help();
12
40
    if (v.size() <2 )
13
4
    {
14
4
        return "what?\n" + help();
15
4
    }
16
36
    if (v[1] == "stop")
17
8
    {
18
8
        std::string s ="close server";
19
8
        useful_F::send_to_arduino_clock(my_data, "STOP");
20
8
        iDomTOOLS::MPD_stop();
21
8
        my_data->iDomProgramState = iDomStateEnum::CLOSE;
22
8
        my_data->main_iDomTools->saveState_iDom();
23
8
        throw s;
24
8
    }
25
28
    if (v.size() < 3 )
26
4
    {
27
4
        return "add more paramiters";
28
4
    }
29
24
    if(v[1] == "reload" && v[2] == "soft"){
30
4
        std::string s ="close server";
31
4
        useful_F::send_to_arduino_clock(my_data, "RELO");
32
4
        iDomTOOLS::MPD_stop();
33
4
        my_data->iDomProgramState = iDomStateEnum::RELOAD;
34
4
        my_data->main_iDomTools->saveState_iDom();
35
4
        throw s;
36
4
    }
37
20
    else if(v[1] == "reload" && v[2] == "hard")
38
4
    {
39
4
        std::string s ="close server";
40
4
        useful_F::send_to_arduino_clock(my_data, "UPAD");
41
4
        iDomTOOLS::MPD_stop();
42
4
        my_data->iDomProgramState = iDomStateEnum::HARD_RELOAD;
43
4
        my_data->main_iDomTools->saveState_iDom();
44
4
        throw s;
45
4
    }
46
16
    else if(v[1] == "clear" && v[2] == "ram")
47
4
    {
48
4
        useful_F::runLinuxCommand("sync; echo 3 > /proc/sys/vm/drop_caches");
49
4
        ret = "ram has beed freed";
50
4
    }
51
12
    else if(v[1] == "debuge" && v[2] == "variable")
52
4
    {
53
4
        std::stringstream r;
54
4
       r << "my_data->alarmTime.fromVolume \t" << my_data->alarmTime.fromVolume <<std::endl;
55
4
        r << "my_data->alarmTime.radioID \t" << my_data->alarmTime.radioID <<std::endl;
56
4
        r << "my_data->alarmTime.state \t" << stateToString( my_data->alarmTime.state) <<std::endl;
57
4
        r << "my_data->alarmTime.time \t" << my_data->alarmTime.time.getString() <<std::endl;
58
4
        r << "my_data->alarmTime.toVolume \t" << my_data->alarmTime.toVolume <<std::endl;
59
4
        r << std::endl;
60
4
        r << "my_data->encriptionKey \t" << my_data->encriptionKey <<std::endl;
61
4
        r << std::endl;
62
4
        r << "my_data->server_settings->BaudRate \t" << my_data->server_settings->BaudRate <<std::endl;
63
4
        r << "my_data->server_settings->cameraLedOFF \t" << my_data->server_settings->cameraLedOFF <<std::endl;
64
4
        r << "my_data->server_settings->cameraLedON \t" << my_data->server_settings->cameraLedON <<std::endl;
65
4
        r << "my_data->server_settings->cameraURL \t" << my_data->server_settings->cameraURL <<std::endl;
66
4
        r << "my_data->server_settings->encrypted \t" << my_data->server_settings->encrypted <<std::endl;
67
4
        r << "my_data->server_settings->facebookAccessToken \t" << my_data->server_settings->facebookAccessToken <<std::endl;
68
4
        r << "my_data->server_settings->ftpServer.URL \t" << my_data->server_settings->ftpServer.URL <<std::endl;
69
4
        r << "my_data->server_settings->ftpServer.user \t" << my_data->server_settings->ftpServer.user <<std::endl;
70
4
        r << "my_data->server_settings->ID_server \t" << my_data->server_settings->ID_server <<std::endl;
71
4
        r << "my_data->server_settings->lightningApiURL \t" << my_data->server_settings->lightningApiURL <<std::endl;
72
4
        r << "my_data->server_settings->MENU_PATH \t" << my_data->server_settings->MENU_PATH<<std::endl;
73
4
        r << "my_data->server_settings->MOVIES_DB_PATH \t" << my_data->server_settings->MOVIES_DB_PATH<<std::endl;
74
4
        r << "my_data->server_settings->MPD_IP \t" << my_data->server_settings->MPD_IP<<std::endl;
75
4
        r << "my_data->server_settings->omxplayerFile \t" << my_data->server_settings->omxplayerFile<<std::endl;
76
4
        r << "my_data->server_settings->PORT \t" << my_data->server_settings->PORT<<std::endl;
77
4
        r << "my_data->server_settings->portRS232 \t" << my_data->server_settings->portRS232<<std::endl;
78
4
        r << "my_data->server_settings->portRS232_clock \t" << my_data->server_settings->portRS232_clock<<std::endl;
79
4
        r << "my_data->server_settings->radio433MHzConfigFile \t" << my_data->server_settings->radio433MHzConfigFile<<std::endl;
80
4
        r << "my_data->server_settings->RFLinkBaudRate \t" << my_data->server_settings->RFLinkBaudRate<<std::endl;
81
4
        r << "my_data->server_settings->RFLinkPort \t" << my_data->server_settings->RFLinkPort<<std::endl;
82
4
        r << "my_data->server_settings->saveFilePath \t" << my_data->server_settings->saveFilePath<<std::endl;
83
4
        r << "my_data->server_settings->SERVER_IP \t" << my_data->server_settings->SERVER_IP<<std::endl;
84
4
        r << "my_data->server_settings->THREAD_CRON \t" << my_data->server_settings->THREAD_CRON<<std::endl;
85
4
        r << "my_data->server_settings->THREAD_DUMMY \t" << my_data->server_settings->THREAD_DUMMY<<std::endl;
86
4
        r << "my_data->server_settings->THREAD_IRDA \t" << my_data->server_settings->THREAD_IRDA<<std::endl;
87
4
        r << "my_data->server_settings->THREAD_MPD \t" << my_data->server_settings->THREAD_MPD<<std::endl;
88
4
        r << "my_data->server_settings->THREAD_RS232 \t" << my_data->server_settings->THREAD_RS232<<std::endl;
89
4
        r << "my_data->server_settings->TS_KEY \t" << my_data->server_settings->TS_KEY<<std::endl;
90
4
        r << "my_data->server_settings->viberAvatar \t" << my_data->server_settings->viberAvatar<<std::endl;
91
4
        r << "my_data->server_settings->viberReceiver.at(0) \t" << my_data->server_settings->viberReceiver.at(0)<<std::endl;
92
4
        r << "my_data->server_settings->viberSender \t" << my_data->server_settings->viberSender<<std::endl;
93
4
        r << "my_data->server_settings->viberToken \t" << my_data->server_settings->viberToken<<std::endl;
94
4
        r << "my_data->server_settings->v_delay \t" << my_data->server_settings->v_delay<<std::endl;
95
4
        r << std::endl;
96
4
        r << "my_data->server_settings->sleeper \t" << my_data->sleeper<<std::endl;
97
4
        r << std::endl;
98
4
        r << "my_data->iDomProgramState \t" << static_cast<int>(my_data->iDomProgramState)<<std::endl;
99
4
        r << std::endl;
100
4
        r << "my_data->main_iDomStatus \t" << my_data->main_iDomStatus->getAllObjectsStateString()<<std::endl;
101
4
        r << std::endl;
102
4
        r << "my_data->idom_all_state.houseState \t" <<stateToString(my_data->idom_all_state.houseState)<<std::endl;
103
4
        r << std::endl;
104
4
        r << "my_data->now_time \t" << my_data->now_time<<std::endl;
105
4
        r << "my_data->start - time \t" << my_data->start<<std::endl;
106
4
        r << std::endl;
107
4
        r << "my_data->pointer.ptr_buf \t" << my_data->pointer.ptr_buf<<std::endl;
108
4
        r << "my_data->pointer.ptr_who \t" << my_data->pointer.ptr_who<<std::endl;
109
4
110
4
        r << std::endl;
111
4
        r << "my_data->ptr_MPD_info->artist \t" << my_data->ptr_MPD_info->artist<<std::endl;
112
4
        r << "my_data->ptr_MPD_info->currentSongID \t" << my_data->ptr_MPD_info->currentSongID<<std::endl;
113
4
        r << "my_data->ptr_MPD_info->isPlay \t" << my_data->ptr_MPD_info->isPlay<<std::endl;
114
4
        r << "my_data->ptr_MPD_info->radio \t" << my_data->ptr_MPD_info->radio<<std::endl;
115
4
        r << "my_data->ptr_MPD_info->songList.at(0) \t" << my_data->ptr_MPD_info->songList.at(0)<<std::endl;
116
4
        r << "my_data->ptr_MPD_info->title \t" << my_data->ptr_MPD_info->title<<std::endl;
117
4
        r << "my_data->ptr_MPD_info->volume \t" << my_data->ptr_MPD_info->volume<<std::endl;
118
4
119
4
        r << std::endl;
120
4
        r << "my_data->main_RFLink->okTime \t" << my_data->main_RFLink->okTime<<std::endl;
121
4
        r << "my_data->main_RFLink->pingTime \t" << my_data->main_RFLink->pingTime<<std::endl;
122
4
123
4
        r << std::endl;
124
4
        r << "my_data->mainLCD-> \t" << my_data->mainLCD->getData() <<std::endl;
125
4
126
4
        r << "END.";
127
4
        ret = r.str();
128
4
    }
129
8
    else if(v[1] == "raspberry")
130
4
    {
131
4
        int i = useful_F::runLinuxCommand(v[2].c_str());
132
4
        ret = "command done with exitcode: " + std::to_string(i);
133
4
    }
134
4
    else
135
4
    {
136
4
        ret = " what? - "+ v[1];
137
4
    }
138
24
    return ret;
139
24
}
140
141
std::string command_program::help()
142
48
{
143
48
    std::stringstream help;
144
48
    help << "program stop - close iDom server"<< std::endl;
145
48
    help << "program reload soft - reload iDom server" << std::endl;
146
48
    help << "program reload hard - reload iDom server" << std::endl;
147
48
    help << "program clear ram   - reload iDom server" << std::endl;
148
48
    help << "program debuge variable - show value iDom server variable" << std::endl;
149
48
    help << "program raspberry <command> - put command to raspberry " << std::endl;
150
48
    return help.str();
151
48
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_put.cpp
Line
Count
Source
1
#include "command_put.h"
2
#include "../../../src/CRON/cron.hpp"
3
4
command_put::command_put(const std::string &name):command(name)
5
32
{
6
32
}
7
8
std::string command_put::execute(std::vector<std::string> &v, thread_data *my_data)
9
4
{
10
4
    std::string str_buf = "command put - wrong paramiter: ";
11
4
    if (v.size() > 1){
12
4
        if (v[1] =="temperature")
13
4
        {
14
4
            str_buf.erase();
15
4
            my_data->main_iDomTools->send_temperature_thingSpeak();
16
4
            str_buf = "DONE";
17
4
        }
18
4
    }
19
4
    return str_buf;
20
4
}
21
22
std::string command_put::help()
23
4
{
24
4
    std::stringstream help;
25
4
    help << "put <parameter> - " << std::endl << std::endl;
26
4
    help << "parameter:" << std::endl;
27
4
    help << "\ttemperature - put actual temperature from inside and outside and smog on thingspeak\n" << std::endl;
28
4
    return help.str();
29
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_show.cpp
Line
Count
Source
1
#include <strstream>
2
#include "command_show.h"
3
#include "../../../src/functions/functions.h"
4
5
command_show::command_show(const std::string &name):command(name)
6
64
{
7
64
8
64
}
9
10
std::string command_show::execute(std::vector<std::string> &v, thread_data *my_data)
11
36
{
12
36
    std::string str_buf = "show what?";
13
36
    if (v.size() > 1){
14
32
        if (v[1] =="log")
15
16
        {
16
16
            if (v.size() >2 && v.size() < 4){
17
4
                 return useful_F::l_send_file(_logfile,v[2],true);
18
4
            }
19
12
            else if (v.size() > 3){
20
8
                if (v[2] == "no"){
21
4
                 return useful_F::l_send_file(_logfile,v[3],false);
22
4
                }
23
4
                else{
24
4
                    return "do you mean : show log no <string>?";
25
4
                }
26
4
            }
27
4
            return useful_F::l_send_file(_logfile,"");
28
4
        }
29
16
        if (v[1]=="thread")
30
12
        {
31
12
            if (v.size() < 3){
32
4
                return "No ID";
33
4
            }
34
8
            else {
35
8
                if (v [2] !="all"){
36
4
                    std::stringstream ss;
37
4
                    ss << my_data->main_THREAD_arr->at(std::stoi(v[2])).thread_ID;
38
4
                    str_buf = my_data->main_THREAD_arr->at(std::stoi(v[2])).thread_name;
39
4
                    str_buf += "ID: ";
40
4
                    str_buf += ss.str();
41
4
                    str_buf += " socket: ";
42
4
                    str_buf += std::to_string(my_data->main_THREAD_arr->at(std::stoi(v[2])).thread_socket);
43
4
                    return str_buf;
44
4
                }
45
4
                else{
46
4
                    str_buf.erase();
47
4
                    std::stringstream ss;
48
44
                    for (int i =0; i< iDomConst::MAX_CONNECTION;++i)
49
40
                    {
50
40
                        ss.clear();
51
40
                        ss = std::stringstream();
52
40
                        str_buf += std::to_string(i)+" ";
53
40
                        str_buf += my_data->main_THREAD_arr->at(i).thread_name;
54
40
                        str_buf += "\t ID: ";
55
40
                        ss << my_data->main_THREAD_arr->at(i).thread_ID;
56
40
                        str_buf += ss.str();
57
40
                        int idSocket = my_data->main_THREAD_arr->at(i).thread_socket;
58
40
59
40
                        if (idSocket != 0 && idSocket != 1){
60
4
                            str_buf += " socket: ";
61
4
                            str_buf += std::to_string(my_data->main_THREAD_arr->at(i).thread_socket);
62
4
                        }
63
40
                        str_buf += "\n";
64
40
                    }
65
4
                    return str_buf;
66
4
                }
67
4
            }
68
4
        }
69
4
        else {
70
4
            return "wrong parameter: "+v[1];
71
4
        }
72
4
    }
73
4
    return str_buf;
74
4
}
75
76
std::string command_show::help()
77
4
{
78
4
    std::stringstream help;
79
4
    help << "show <parameter>- for show something" <<std::endl << std::endl;
80
4
    help << "parameter:" << std::endl;
81
4
    help << "\tlog             - show all server log" << std::endl;
82
4
    help << "\tlog <string>    - show all server log lines which contain <string>" << std::endl;
83
4
    help << "\tlog no <string> - show all server log lines which NO contain <string>" << std::endl;
84
4
    help << "\tthread all      - show all server thread pid " << std::endl;
85
4
    help << "\tthread <number> - show server <number> thread pid " << std::endl;
86
4
87
4
    return help.str();
88
4
}
89
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_sleep.cpp
Line
Count
Source
1
#include "command_sleep.h"
2
#include "../../functions/functions.h"
3
#include "../../thread_functions/iDom_thread.h"
4
5
command_sleep::command_sleep(const std::string &name):command(name)
6
48
{
7
48
}
8
9
std::string command_sleep::execute(std::vector<std::string> &v, thread_data *my_data)
10
20
{   if (v.size()== 1)
11
4
    {
12
4
        return "sleep set to: "+ std::to_string(my_data->sleeper);
13
4
    }
14
16
    else if (v.size() == 3 ){
15
12
        if (v[1] == "set"){
16
8
            int sleep = 0;
17
8
            try {
18
8
                sleep = std::stoi(v[2]);
19
8
            }
20
8
            catch (...){
21
4
                return "system need intiger > 0 not: " +v[2];
22
4
            }
23
4
24
4
            my_data->sleeper = sleep;
25
4
26
4
            return iDOM_THREAD::start_thread("Sleep MPD",useful_F::sleeper_mpd,my_data);
27
4
        }
28
4
        else {
29
4
            return "wrong parametr "+v[1];
30
4
        }
31
4
    }
32
4
    return "internal error";
33
4
}
34
35
std::string command_sleep::help()
36
4
{
37
4
    std::stringstream help;
38
4
    help << "sleep - show actual time to stop play music" << std::endl;
39
4
    help << "sleep set <int> - start sleep for <int> minutes" << std::endl;
40
4
41
4
    return help.str();
42
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_state.cpp
Line
Count
Source
1
#include "command_state.h"
2
3
command_state::command_state(const std::string &name):command(name)
4
40
{
5
40
}
6
7
std::string command_state::execute(std::vector<std::string> &v, thread_data *my_data)
8
12
{
9
12
    std::string ret = "need parameter!\n" + help();
10
12
    if (v.size() > 1)
11
8
    {
12
8
13
8
        if (v[1] == "all")
14
4
        {
15
4
            return my_data->main_iDomStatus->getAllObjectsStateString();
16
4
        }
17
4
        if (v[1] != "all")
18
4
        {
19
4
            return my_data->main_iDomStatus->getObjectStateString(v[1]);
20
4
        }
21
4
22
4
    }
23
4
    return ret;
24
4
}
25
26
std::string command_state::help()
27
16
{
28
16
    std::stringstream help;
29
16
    help << "state all/<name> - show state" << std::endl;
30
16
    return help.str();
31
16
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/command_uptime.cpp
Line
Count
Source
1
#include "command_uptime.h"
2
#include "../../../src/functions/functions.h"
3
4
command_UPTIME::command_UPTIME(const std::string &name):command(name)
5
32
{
6
32
7
32
}
8
9
std::string command_UPTIME::execute(std::vector<std::string> &v, thread_data *my_data)
10
4
{
11
4
    std::string str_buf;
12
4
    time(&my_data->now_time);
13
4
    str_buf ="uptime: ";
14
4
    str_buf.append(useful_F::sek_to_uptime(difftime(my_data->now_time,my_data->start) ) );
15
4
    return str_buf;
16
4
}
17
18
std::string command_UPTIME::help()
19
4
{
20
4
    std::stringstream help;
21
4
    help << "uptime - show server uptime" << std::endl;
22
4
    return help.str();
23
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/commandexit.cpp
Line
Count
Source
1
#include "commandexit.h"
2
3
commandEXIT::commandEXIT(const std::string &name):command(name)
4
32
{
5
32
}
6
7
std::string commandEXIT::execute(std::vector<std::string> &v, thread_data *my_data)
8
4
{
9
4
    return "\nEND.\n";
10
4
}
11
12
std::string commandEXIT::help()
13
4
{
14
4
    return "exit - disconnect from server\n";
15
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/commandrs232.cpp
Line
Count
Source
1
#include "commandrs232.h"
2
#include "../../../src/functions/functions.h"
3
4
commandRS232::commandRS232(const std::string &name):command(name)
5
60
{
6
60
}
7
std::string commandRS232::execute(std::vector<std::string> &v, thread_data *my_data)
8
32
{
9
32
    std::string str_buf ="default";
10
32
11
32
    if (v[1]=="get")
12
8
    {
13
8
        if (v[2]=="temperature")
14
4
        {
15
4
            str_buf = useful_F::send_to_arduino(my_data,"temperature:339;");
16
4
            str_buf += std::to_string(++counter);
17
4
        }
18
4
        else
19
4
        {
20
4
            str_buf = ("wrong parameter: "+v[2]);
21
4
        }
22
8
    }
23
24
24
24
    else if (v[1]=="send")
25
4
    {
26
4
        str_buf = useful_F::send_to_arduino(my_data,v[2]);
27
4
    }
28
20
    else if (v[1]=="error")
29
16
    {
30
16
        if (v.size() < 3 )
31
4
            return "add more parameter to error";
32
12
        std::string msg;
33
40
        for (unsigned int i = 2; i < v.size(); ++i)
34
28
        {
35
28
            msg+=" ";
36
28
            msg+=v[i];
37
28
        }
38
12
        if(v[2]=="Temperature" && v[3]=="error")
39
4
        {
40
4
41
4
            my_data->myEventHandler.run("RS232")->addEvent("RS232 error event: "+msg);
42
4
            log_file_mutex.mutex_lock();
43
4
            log_file_cout << WARNING<< "RS232 ERROR event: " << msg << std::endl;
44
4
            log_file_mutex.mutex_unlock();
45
4
        }
46
8
        else if (v[2]=="test" && v[3]=="msg")
47
4
        {
48
4
            log_file_mutex.mutex_lock();
49
4
            log_file_cout << DEBUG << "RS232 ERROR debug : "<<msg << std::endl;
50
4
            log_file_mutex.mutex_unlock();
51
4
            str_buf = "DONE!";
52
4
        }
53
4
        else
54
4
        {
55
4
            log_file_mutex.mutex_lock();
56
4
            log_file_cout << CRITICAL << "RS232 ERROR unknown : "<<msg << std::endl;
57
4
            log_file_mutex.mutex_unlock();
58
4
        }
59
12
    }
60
4
    else
61
4
    {
62
4
        str_buf = ("wrong parameter: "+v[1]);
63
4
    }
64
32
    return str_buf;
65
32
}
66
67
std::string commandRS232::help()
68
4
{
69
4
    std::stringstream help;
70
4
    help << "RS232 - communication with Arduino:" << std::endl;
71
4
    help << "parameter:" << std::endl << std::endl;
72
4
    help << "\tsend <command> - send <command> to Arduino" << std::endl;
73
4
    help << "\tget <param> - get <param> from Arduino" << std::endl;
74
4
    help << "\t\ttemperature - get temeprature INSIDE + OUTSIDE" << std::endl;
75
4
76
4
    return help.str();
77
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandClass/commandtest.cpp
Line
Count
Source
1
#include "commandtest.h"
2
#include "../../functions/functions.h"
3
#include "../../../ftplibpp/ftplib.h"
4
5
commandTEST::commandTEST(const std::string &name):command(name)
6
40
{
7
40
}
8
9
std::string commandTEST::execute(std::vector<std::string> &v, thread_data *my_data)
10
12
{
11
12
12
12
    if (v[1] == "test")
13
4
    {
14
4
        std::string msg = "test - for test";
15
4
        my_data->main_iDomTools->runOnSunrise();
16
4
        return msg;
17
4
    }
18
8
    else if (v[1] == "throw")
19
4
    {
20
4
        throw std::string("test throw");
21
4
    }
22
4
    return help();
23
4
}
24
std::string commandTEST::help()
25
8
{
26
8
    std::stringstream help;
27
8
    help << "test - for test" << std::endl;
28
8
    help << "throw - trow test reload program" << std::endl;
29
8
    return help.str();
30
8
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandhandler.cpp
Line
Count
Source
1
#include <iostream>
2
#include "../../libs/emoji/emoji.h"
3
#include "commandhandler.h"
4
#include "commandClass/command_mpd.h"
5
#include "commandClass/commandrs232.h"
6
#include "commandClass/command_uptime.h"
7
#include "commandClass/command_big.h"
8
#include "commandClass/command_clock.h"
9
#include "commandClass/command_hello.h"
10
#include "commandClass/command_help.h"
11
#include "commandClass/command_ip.h"
12
#include "commandClass/command_put.h"
13
#include "commandClass/command_sleep.h"
14
#include "commandClass/command_ok.h"
15
#include "commandClass/command_show.h"
16
#include "commandClass/command_idom.h"
17
#include "commandClass/command_program.h"
18
#include "commandClass/commandexit.h"
19
#include "commandClass/commandtest.h"
20
#include "commandClass/command_log.h"
21
#include "commandClass/command_state.h"
22
#include "commandClass/command_ardu.h"
23
24
commandHandler::commandHandler(thread_data * my_data)
25
28
{
26
28
    std::unique_ptr <command> test(new commandTEST("test") );
27
28
    commandMap.insert( std::make_pair(test->getCommandName(),std::move( test )) );
28
28
29
28
    std::unique_ptr <command> program(new command_program("program") );
30
28
    commandMap.insert( std::make_pair(program->getCommandName(),std::move( program )) );
31
28
32
28
    std::unique_ptr <command> eexit(new commandEXIT("exit"));
33
28
    commandMap.insert( std::make_pair(eexit->getCommandName(),std::move( eexit )) );
34
28
35
28
    std::unique_ptr <command> MPD(new command_mpd("MPD"));
36
28
    commandMap.insert(std::make_pair(MPD->getCommandName(), std::move (MPD)));
37
28
38
28
    std::unique_ptr <command> RS232 (new commandRS232("RS232"));
39
28
    commandMap.insert(std::make_pair(RS232->getCommandName(), std::move(RS232)));
40
28
41
28
    std::unique_ptr <command> uptime (new command_UPTIME("uptime"));
42
28
    commandMap.insert(std::make_pair(uptime->getCommandName(), std::move(uptime)));
43
28
44
28
    std::unique_ptr <command> big (new command_big("big"));
45
28
    commandMap.insert(std::make_pair(big->getCommandName(), std::move(big)));
46
28
47
28
    std::unique_ptr <command> clock (new command_clock("clock"));
48
28
    commandMap.insert(std::make_pair(clock->getCommandName(), std::move(clock)));
49
28
50
28
    std::unique_ptr <command> hello (new command_hello("hello"));
51
28
    commandMap.insert(std::make_pair(hello->getCommandName(), std::move(hello)));
52
28
53
28
    std::unique_ptr <command> help (new command_help("help"));
54
28
    commandMap.insert(std::make_pair(help->getCommandName(), std::move(help)));
55
28
56
28
    std::unique_ptr <command> ip (new command_ip("ip"));
57
28
    commandMap.insert(std::make_pair(ip->getCommandName(), std::move(ip)));
58
28
59
28
    std::unique_ptr <command> ok (new command_ok("ok"));
60
28
    commandMap.insert(std::make_pair(ok->getCommandName(), std::move(ok)));
61
28
62
28
    std::unique_ptr <command> show (new command_show("show"));
63
28
    commandMap.insert(std::make_pair(show->getCommandName(), std::move(show)));
64
28
65
28
    std::unique_ptr <command> sleep (new command_sleep("sleep"));
66
28
    commandMap.insert(std::make_pair(sleep->getCommandName(), std::move(sleep)));
67
28
68
28
    std::unique_ptr <command> put (new command_put("put"));
69
28
    commandMap.insert(std::make_pair(put->getCommandName(), std::move(put)));
70
28
71
28
    std::unique_ptr <command> iDom (new command_iDom("iDom"));
72
28
    commandMap.insert(std::make_pair(iDom->getCommandName(), std::move(iDom)));
73
28
74
28
    std::unique_ptr <command> log (new command_log("log"));
75
28
    commandMap.insert(std::make_pair(log->getCommandName(), std::move(log)));
76
28
77
28
    std::unique_ptr <command> state (new command_state("state"));
78
28
    commandMap.insert(std::make_pair(state->getCommandName(), std::move(state)));
79
28
80
28
    std::unique_ptr <command> ardu (new command_ardu("ardu", my_data));
81
28
    commandMap.insert(std::make_pair(ardu->getCommandName(), std::move(ardu)));
82
28
83
28
    this->my_data = my_data;
84
28
    this->my_data->commandMapPtr = &commandMap;
85
28
}
86
87
commandHandler::~commandHandler()
88
28
{
89
28
    puts("commandHandler::~commandHandler()");
90
28
}
91
92
std::string commandHandler::run(std::vector<std::string> &v, thread_data *my_data)
93
12
{
94
12
    if (commandMap.find(v[0]) == commandMap.end()){
95
4
        std::fstream log;
96
4
        log.open( "/mnt/ramdisk/command.txt", std::ios::binary | std::ios::in | std::ios::out|std::ios::app );
97
4
        log << v[0] << std::endl;
98
4
        log.close();
99
4
        return EMOJI::emoji(E_emoji::WARNING_SIGN)+" unknown command: "+ v[0];
100
4
    }
101
8
    else{
102
8
        return commandMap[v[0]]->execute(v,my_data);
103
8
    }
104
12
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandhandlerroot.cpp
Line
Count
Source
1
#include "commandhandlerroot.h"
2
#include "commandClass/command_cmd.h"
3
#include "commandClass/command_event.h"
4
#include "commandClass/command_433mhz.h"
5
6
commandHandlerRoot::commandHandlerRoot(thread_data * my_data): commandHandler(my_data)
7
28
{
8
28
    std::unique_ptr <command> cmd (new command_cmd("cmd"));
9
28
    commandMap.insert(std::make_pair(cmd->getCommandName(), std::move(cmd)));
10
28
11
28
    std::unique_ptr <command> event (new command_event("event"));
12
28
    commandMap.insert(std::make_pair(event->getCommandName(), std::move(event)));
13
28
14
28
    std::unique_ptr <command> r_433MHz (new command_433MHz("433MHz"));
15
28
    commandMap.insert(std::make_pair(r_433MHz->getCommandName(), std::move(r_433MHz)));
16
28
}
17
18
commandHandlerRoot::~commandHandlerRoot()
19
28
{
20
28
    puts("commandHandlerRoot::~commandHandlerRoot()");
21
28
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/commandhandlerrs232.cpp
Line
Count
Source
1
#include "commandhandlerrs232.h"
2
#include "commandClass/command_cmd.h"
3
#include "commandClass/command_event.h"
4
5
6
commandHandlerRS232::commandHandlerRS232(thread_data *my_data):commandHandlerRoot(my_data)
7
4
{
8
4
9
4
}
10
11
commandHandlerRS232::~commandHandlerRS232()
12
4
{
13
4
    puts("commandHandlerRS232::~commandHandlerRS232()");
14
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/test/commandhandler_BT.cpp
Line
Count
Source
1
#include "../commandhandlerrs232.h"
2
#include "../../iDomTools/test/iDomTools_fixture.h"
3
4
class command_handler_rs232_fixture : public iDomTOOLS_ClassTest
5
{
6
public:
7
    command_handler_rs232_fixture()
8
4
    {
9
4
10
4
    }
11
12
protected:
13
    std::unique_ptr<commandHandlerRS232> test_chRS232;
14
    std::vector<std::string> test_v;
15
    void SetUp() final
16
4
    {
17
4
        iDomTOOLS_ClassTest::SetUp();
18
4
        test_chRS232 = std::make_unique<commandHandlerRS232>(&test_my_data);
19
4
    }
20
21
    void TearDown() final
22
4
    {
23
4
        iDomTOOLS_ClassTest::TearDown();
24
4
    }
25
};
26
27
TEST_F(command_handler_rs232_fixture, main)
28
4
{
29
4
    test_v.push_back("ok");
30
4
    auto ret = test_chRS232->run(test_v, &test_my_data);
31
4
    EXPECT_STREQ(ret.c_str(), "\nEND\n");
32
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/command/test/commandhandler_stub.cpp
Line
Count
Source
1
#include "../../src/functions/functions.h"
2
#include "../../src/LCD_c/lcd_c.h"
3
4
//std::string useful_F::send_to_arduino (thread_data *my_data_logic, const std::string& msg){
5
//    return "retunr test ";
6
//}
7
8
20
std::string useful_F::send_to_arduino_clock (thread_data *my_data_logic, std::string msg){
9
20
    return "return test";
10
20
}
11
//std::string useful_F::l_send_file(std::string path, std::string find, bool reverse )
12
//{
13
//    return "return test in l_send_file()";
14
//}
15
16
4
std::string LCD_c::getData(){
17
4
    return " data test";
18
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/files_tree/files_tree.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "files_tree.h"
2
3
bool comper (const movie_database & a , const movie_database& b)
4
848
{
5
848
    return a.files_name < b.files_name;
6
848
}
7
files_tree::files_tree (const std::string& path, LCD_c *mainLCD_PTR):database_path(path),w_serial( "([Ss]\\d{1,3}[Ee]\\d{1,3})")
8
9
48
{
10
48
    //database_path = path;
11
48
    mainLCD = mainLCD_PTR;
12
48
    //tree_stack.push(database_path);
13
48
    i_stack.push(0);
14
48
    i = 0;
15
48
    get_list(database_path);
16
48
}
17
bool files_tree::is_file() const
18
12
{
19
12
    return movie_database_vector[i].is_file;
20
12
}
21
22
void files_tree::next()
23
12
{   
24
12
    ++i;
25
12
    ////std::cout << " dodaje " << i << std::endl;
26
12
    if (get_vector_size() == i ){
27
4
        i=0;
28
4
    }
29
12
}
30
31
void files_tree::previous()
32
20
{
33
20
    --i;
34
20
    ////std::cout << " odejmuje " << i << std::endl;
35
20
36
20
    if ( i <0 )
37
8
    {
38
8
        i=get_vector_size()-1;
39
8
    }
40
20
}
41
42
int files_tree::get_vector_size () const
43
20
{
44
20
    return movie_database_vector.size();
45
20
}
46
void files_tree::vector_clear ()
47
56
{
48
56
    movie_database_vector.clear();
49
56
}
50
int files_tree::get_i()
51
4
{ if (i_stack.size() >1 ) {
52
4
        int i = i_stack.top();
53
4
        i_stack.pop();
54
4
        return i;
55
4
    }
56
0
    else
57
0
        return 0;
58
4
}
59
60
void files_tree::enter_dir()
61
4
{
62
4
    i_stack.push(i); // wpisuje na stos kolejna wersje licznika i
63
4
64
4
    if (movie_database_vector[i].is_file == false) {
65
4
        get_list (movie_database_vector[i].path);
66
4
        i=0;
67
4
    }
68
4
69
4
}
70
void files_tree::enter_dir(const std::string& path)
71
0
{ //tree_stack.push(path);
72
0
    get_list (path);
73
0
}
74
75
void files_tree::back_dir()
76
4
{
77
4
    if ( tree_stack.size() >1 ) {
78
4
        tree_stack.pop();
79
4
        std::string path = tree_stack.top();
80
4
        tree_stack.pop();
81
4
        i = get_i();
82
4
        get_list (path);
83
4
        return;
84
4
    }
85
0
    i = get_i();
86
0
87
0
    ////std::cout << " III ma teraz : " << i << std::endl;
88
0
    get_list (database_path);
89
0
    return;
90
0
}
91
92
std::string files_tree::show_list()
93
96
{
94
96
    //std::cout << "iteracja!!!!!!!!!!!!!!!!!!!!!!: " << i <<"rozmiar vectora : " << get_vector_size() << std::endl;
95
96
    if (movie_database_vector[i].is_file == true ) {
96
48
        //std::cout << "wypisuje sciezke pliku " << movie_database_vector[i].path <<" | " <<movie_database_vector[i].files_name.substr(0,16)<< std::endl;
97
48
98
48
        mainLCD->printString(true,0,0,movie_database_vector[i].files_name.substr(0,16));
99
48
        if( regex_search(movie_database_vector[i].path,result,w_serial) )
100
48
        {
101
48
            mainLCD->printString(false,10,1,movie_database_vector[i].files_name.substr( movie_database_vector[i].files_name.size()-4,movie_database_vector[i].files_name.size()));
102
48
            mainLCD->printString(false, 1,1,result[0]);
103
48
        }
104
0
        else
105
0
        {
106
0
            mainLCD->printString(false,10,1,movie_database_vector[i].files_name.substr( movie_database_vector[i].files_name.size()-4,movie_database_vector[i].files_name.size()));
107
0
        }
108
48
    }
109
48
    else {
110
48
        mainLCD->printString(true,0,0,movie_database_vector[i].files_name+"/");
111
48
    }
112
96
    return movie_database_vector[i].path;
113
96
}
114
115
56
void files_tree::get_list(std::string path) {
116
56
    tree_stack.push(path);
117
56
    vector_clear(); // czyscimy vector
118
56
    std::string path2 =path;
119
56
    std::string v_path ,tmp_string;
120
56
121
56
    if(sciezka = opendir( path.c_str() )) {
122
56
123
328
        while(( plik = readdir( sciezka ) ) )
124
272
        {
125
272
            path2 =path;
126
272
            if (static_cast<int>(plik->d_type) == 4 /*&& strcmp( plik->d_name, "..") && strcmp( plik->d_name, ".")*/)
127
164
            {
128
164
                temp.is_file=false;
129
164
            }
130
108
            else //if ( (int)plik->d_type == 8 && strcmp( plik->d_name, "..") && strcmp( plik->d_name, "."))
131
108
            {
132
108
                temp.is_file=true;
133
108
            }
134
272
135
272
            v_path= path2;
136
272
            v_path+="/";
137
272
            tmp_string.assign(plik->d_name);
138
272
            v_path+=tmp_string;
139
272
            temp.path =v_path;
140
272
            temp.files_name.assign(plik->d_name);
141
272
            movie_database_vector.push_back(temp);
142
272
        }// end while
143
56
        sort(movie_database_vector.begin(),movie_database_vector.end(), comper);
144
56
        closedir( sciezka );
145
56
    }
146
56
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/functions/functions2.cpp
Line
Count
Source (jump to first uncovered line)
1
#include <iostream>
2
#include <fstream>
3
#include <regex>
4
#include <iterator>
5
#include <vector>
6
7
#include "functions.h"
8
#include "../thread_functions/iDom_thread.h"
9
10
92
std::vector<std::string> useful_F::split(const std::string& s, char separator ){
11
92
    std::vector<std::string> output;
12
92
    std::string::size_type prev_pos = 0, pos = 0;
13
92
14
212
    while((pos = s.find(separator, pos)) != std::string::npos)
15
120
    {
16
120
        std::string substring( s.substr(prev_pos, pos-prev_pos) );
17
120
        output.push_back(substring);
18
120
        prev_pos = ++pos;
19
120
    }
20
92
    try
21
92
    {
22
92
        output.push_back(s.substr(prev_pos, pos-prev_pos)); // Last word
23
92
    }
24
92
    catch (...)
25
92
    {
26
0
        log_file_mutex.mutex_lock();
27
0
        log_file_cout << CRITICAL << "wyjatek substr() w useful_F::split() !!!!!!"<< std::endl;
28
0
        log_file_mutex.mutex_unlock();
29
0
    }
30
92
    return output;
31
92
}
32
thread_data* useful_F::myStaticData = std::nullptr_t();
33
void useful_F::setStaticData(thread_data *my_dataPtr)
34
4
{
35
4
    myStaticData = my_dataPtr;
36
4
}
37
38
20
void useful_F::tokenizer ( std::vector <std::string> &command, std::string separator, std::string &text){
39
20
    std::string temp;
40
20
41
20
    for(char n: text)
42
176
    { // the initializer may be an array
43
176
        bool is_sep = false;
44
176
        for(char m: separator)
45
476
        {
46
476
            if (n == m)
47
20
                is_sep = true;
48
476
        }
49
176
        if (is_sep == false)
50
156
            temp += n;
51
20
        else
52
20
        {
53
20
            if (!temp.empty())
54
20
            {
55
20
                command.push_back( temp);
56
20
                temp = "";
57
20
            }
58
20
        }
59
176
    }
60
20
    if (!temp.empty())
61
12
        command.push_back(temp);
62
20
63
20
    if (command.size() == 0)
64
8
        throw std::string("command empty");
65
12
}
66
67
////// watek sleeper
68
void useful_F::sleeper_mpd (thread_data *my_data, const std::string& threadName)
69
12
{
70
12
    unsigned int t = 60/my_data->sleeper;
71
12
    unsigned int k = 0;
72
12
73
64
    for (; my_data->sleeper >0; my_data->sleeper-- )
74
52
    {
75
52
        useful_F::sleep(60);
76
52
        k += t;
77
52
        my_data->main_iDomTools->ledClear(0,k);
78
52
    }
79
12
    my_data->main_iDomTools->ledOFF();
80
12
    my_data->main_iDomTools->MPD_stop();
81
12
    my_data->main_iDomTools->turnOff433MHzSwitch("listwa");
82
12
83
12
    log_file_mutex.mutex_lock();
84
12
    log_file_cout << INFO<< "zaczynam procedure konca watku " << threadName << std::endl;
85
12
    log_file_mutex.mutex_unlock();
86
12
87
12
    iDOM_THREAD::stop_thread(threadName,my_data);
88
12
89
12
    log_file_mutex.mutex_lock();
90
12
    log_file_cout << INFO<< "koniec watku SLEEP_MPD" << std::endl;
91
12
    log_file_mutex.mutex_unlock();
92
12
}
93
94
///////////////////////////////////////////////////////////////////////////////////////////////////// watek kodi
95
void useful_F::kodi (thread_data *my_data, const std::string& threadName)
96
8
{
97
8
    log_file_mutex.mutex_lock();
98
8
    log_file_cout << INFO<< "start wątku "<<threadName << std::endl;
99
8
    log_file_mutex.mutex_unlock();
100
8
101
8
    my_data->mainLCD->set_print_song_state(100);
102
8
    my_data->mainLCD->printString(false,2,1,"  KODI");
103
8
104
8
    my_data->main_iDomStatus->setObjectState("KODI",STATE::ACTIVE);
105
8
    //status mpd
106
8
    STATE musicState = my_data->main_iDomStatus->getObjectState("music");
107
8
    // status glosnikow
108
8
    STATE speakersState = my_data->main_iDomStatus->getObjectState("speakers");
109
8
110
8
    if (musicState != STATE::STOP)
111
8
        my_data->main_iDomTools->MPD_pause();
112
8
    if (speakersState != STATE::ON)
113
4
        my_data->main_iDomTools->turnOnSpeakers();
114
8
    //system
115
8
116
8
    int ret = useful_F::runLinuxCommand("runuser -u pi kodi");
117
8
118
8
    if(ret != 0)
119
0
    {
120
0
        log_file_mutex.mutex_lock();
121
0
        log_file_cout << CRITICAL<< "kodi zamkniete z błędem "<<ret << std::endl;
122
0
        log_file_mutex.mutex_unlock();
123
0
    }
124
8
    //przywracanie danych
125
8
126
8
    if(musicState == STATE::PLAY)
127
4
        my_data->main_iDomTools->MPD_play(my_data);
128
4
    else
129
4
        my_data->main_iDomTools->turnOffSpeakers();
130
8
    //koniec
131
8
132
8
    my_data->main_iDomStatus->setObjectState("KODI",STATE::DEACTIVE);
133
8
    my_data->mainLCD->set_print_song_state(0);
134
8
    iDOM_THREAD::stop_thread("kodi smartTV",my_data);
135
8
}
136
std::string useful_F::RSHash(const std::string& data, unsigned int b, unsigned int a)
137
16
{
138
16
    time_t act_time;
139
16
    struct tm * act_date;
140
16
    time(&act_time);
141
16
    act_date = localtime(&act_time);
142
16
    char buffer[10];
143
16
    strftime(buffer,10,"%M%H%w",act_date);
144
16
    std::string str(buffer);
145
16
    str+=data;
146
16
    unsigned int hash = 0;
147
16
148
224
    for(std::size_t i = 0; i < str.length(); i++)
149
208
    {
150
208
        hash = hash * a + str[i];
151
208
        a = a * b;
152
208
    }
153
16
    return std::to_string((hash & 0x7FFFFFFF));
154
16
}
155
156
std::string useful_F::sek_to_uptime(long long secy )
157
8
{
158
8
    const int min = 60; //s
159
8
    const int houry = 3600; //s
160
8
    const int day = 86400; //s
161
8
    int number_day, number_hour, number_min, number_sec;
162
8
    int temp1, temp2, temp3;
163
8
    number_day = secy / day;
164
8
    std::stringstream text;
165
8
    text << "\n" << number_day << " day ";
166
8
    temp1 = secy % day;
167
8
    number_hour = temp1 / houry;
168
8
    text << number_hour << " hours ";
169
8
    temp2 = temp1 % houry;
170
8
    number_min = temp2 / min;
171
8
    text << number_min << " minutes ";
172
8
    temp3 = temp2 % min;
173
8
    number_sec = temp3;
174
8
    text << number_sec << " seconds";
175
8
    return text.str();
176
8
}
177
178
//wysylanie pliku
179
std::string useful_F::l_send_file(std::string path, std::string find, bool reverse )
180
12
{
181
12
    std::string str_buf;
182
12
    if(find.empty()==true)
183
4
    {
184
4
        std::fstream log_file;
185
4
        log_file.open(path.c_str(),std::ios::in);
186
4
        if( log_file.good() == false )
187
0
        {
188
0
            return " can not open file !";
189
0
        }
190
4
        else
191
4
        {
192
4
            str_buf.erase();
193
69.6k
            while( !log_file.eof() )
194
69.6k
            {
195
69.6k
                str_buf += log_file.get();
196
69.6k
            }
197
4
            str_buf.erase(str_buf.length()-1, str_buf.length());
198
4
199
4
            log_file.close();
200
4
        }
201
4
    }
202
8
    else
203
8
    {
204
8
        std::fstream log_file;
205
8
        log_file.open(path.c_str(),std::ios::in);
206
8
        if( log_file.good() == false )
207
0
        {
208
0
            return " can not open file !";
209
0
        }
210
8
        else
211
8
        {
212
8
            str_buf.erase();
213
8
            std::string str_temp;
214
1.85k
            while( std::getline(log_file,str_temp) )
215
1.85k
            {
216
1.85k
                if (reverse)
217
925
                {
218
925
                    if(std::string::npos!=str_temp.find(find))
219
510
                    {
220
510
                        str_buf+=str_temp +"\n";
221
510
                    }
222
415
                    else
223
415
                    {
224
415
                        if(str_buf.size()<3)
225
4
                        {
226
4
                            str_buf+="    ";
227
4
                        }
228
415
                    }
229
925
                }
230
925
                else
231
925
                {
232
925
                    if(std::string::npos == str_temp.find(find))
233
415
                    {
234
415
                        str_buf+=str_temp+"\n";
235
415
                    }
236
925
                }
237
1.85k
                if(str_buf.size()<3)
238
0
                {
239
0
                    str_buf+="    ";
240
0
                }
241
1.85k
            }
242
8
        }
243
8
        log_file.close();
244
8
    }
245
12
    return str_buf;
246
12
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/functions/tests/functions_BT.cpp
Line
Count
Source
1
#include <gtest/gtest.h>
2
#include "../functions.h"
3
#include "../../RADIO_433_eq/radio_433_eq.h"
4
#include "../../iDomTools/test/iDomTools_fixture.h"
5
6
class functions_fixture : public iDomTOOLS_ClassTest{
7
8
};
9
10
void useful_F::sleep(int sec)
11
100
{
12
100
    std::cout << "sleep() sec: " << sec <<std::endl;
13
100
}
14
15
TEST(functions_, tokenizer)
16
4
{
17
4
     std::string test_msg = "one=two three";
18
4
     std::vector<std::string> test_v;
19
4
20
4
     EXPECT_EQ(test_v.size(), 0);
21
4
     useful_F::tokenizer(test_v,"= ",test_msg);
22
4
23
4
     EXPECT_EQ(test_v.size(),3);
24
4
     EXPECT_STREQ(test_v.at(2).c_str(),"three");
25
4
}
26
27
TEST(functions_, sekToUptime)
28
4
{
29
4
    EXPECT_STREQ(useful_F::sek_to_uptime(34534).c_str(),"\n0 day 9 hours 35 minutes 34 seconds");
30
4
}
31
32
TEST(functions_, tokenizerEmpty)
33
4
{
34
4
     std::string test_msg = "";
35
4
     std::vector<std::string> test_v;
36
4
37
4
     EXPECT_EQ(test_v.size(), 0);
38
4
     EXPECT_THROW(useful_F::tokenizer(test_v,"= ",test_msg),std::string);
39
4
}
40
41
TEST(functions_, removeHtmlTag)
42
4
{
43
4
     std::string test_msg = "<html>test</html>";
44
4
     std::string test_pure_str = useful_F_libs::removeHtmlTag(test_msg);
45
4
46
4
     EXPECT_STREQ(test_pure_str.c_str(),"test");
47
4
}
48
49
TEST(functions_, repalceAll)
50
4
{
51
4
     std::string test_msg = "one two three";
52
4
     std::string test_pure_str = useful_F_libs::replaceAll(test_msg,"two","zero");
53
4
54
4
     EXPECT_STREQ(test_pure_str.c_str(),"one zero three");
55
4
}
56
57
TEST(functions_, split)
58
4
{
59
4
    std::string test_msg = "one two three";
60
4
    std::vector<std::string> test_v;
61
4
62
4
    EXPECT_EQ(test_v.size(), 0);
63
4
    test_v = useful_F::split(test_msg,' ');
64
4
65
4
    EXPECT_EQ(test_v.size(),3);
66
4
    EXPECT_STREQ(test_v.at(2).c_str(),"three");
67
4
}
68
69
TEST(functions_, RSHash)
70
4
{
71
4
    std::string msg = "test msg";
72
4
    std::string s1  = useful_F::RSHash(msg, 33, 44);
73
4
    std::string s2  = useful_F::RSHash(msg, 33 ,44);
74
4
    EXPECT_STREQ(s1.c_str(), s2.c_str());
75
4
76
4
    s1 = useful_F::RSHash(msg, 35, 44);
77
4
    s2 = useful_F::RSHash(msg, 33 ,44);
78
4
    EXPECT_STRNE(s1.c_str(), s2.c_str());
79
4
}
80
81
TEST_F(functions_fixture, setStaticData)
82
4
{
83
4
    test_my_data.sleeper = 99;
84
4
    EXPECT_EQ( useful_F::myStaticData->sleeper, 99 );
85
4
    thread_data test_my_data2;
86
4
    test_my_data2.sleeper = 88;
87
4
    EXPECT_EQ( test_my_data2.sleeper, 88 );
88
4
    EXPECT_EQ( useful_F::myStaticData->sleeper, 99 );
89
4
    useful_F::setStaticData(&test_my_data2);
90
4
    EXPECT_EQ( useful_F::myStaticData->sleeper, 88 );
91
4
}
92
93
TEST_F(functions_fixture, sleepThread)
94
4
{
95
4
    std::array <Thread_array_struc,10> test_THRARRSTR;
96
4
    test_my_data.main_THREAD_arr = &test_THRARRSTR;
97
4
98
4
    MPD_info test_ptr_MPD;
99
4
    test_ptr_MPD.volume = 3;
100
4
    test_my_data.ptr_MPD_info = &test_ptr_MPD;
101
4
102
4
   // RADIO_EQ_CONTAINER_STUB test_rec(&test_my_data);
103
4
    std::shared_ptr<RADIO_EQ_CONTAINER> test_rec = std::make_shared<RADIO_EQ_CONTAINER>(&test_my_data);
104
4
    test_rec->loadConfig(test_server_set.radio433MHzConfigFile);
105
4
    test_my_data.main_REC = (test_rec);
106
4
    test_my_data.alarmTime.time = Clock::getTime();
107
4
    test_my_data.alarmTime.state = STATE::ACTIVE;
108
4
109
4
    test_my_data.sleeper = 10;
110
4
111
4
    blockQueue test_q;
112
4
    test_q._clearAll();
113
4
    EXPECT_EQ(test_q._size(),0);
114
4
    useful_F::sleeper_mpd(&test_my_data,"test sleep");
115
4
    EXPECT_EQ(test_q._size(),1);
116
8
    EXPECT_EQ(test_q._get(), MPD_COMMAND::STOP) << "NIE ZATRZYMANO MUZYKI :(";
117
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/functions/tests/functions_stub.cpp
Line
Count
Source
1
#include "../functions.h"
2
#include "test_data.h"
3
4
44
int useful_F::runLinuxCommand(const std::string& cmd){
5
44
    std::cout << "runLinuxCommand(): " << cmd << std::endl;
6
44
    return TEST_DATA::runLinuxCommandReturn;
7
44
}
8
9
bool useful_F::go_while = true;
10
bool useful_F::workServer = true;
11
12
204
std::string useful_F::send_to_arduino(thread_data *my_data, const std::string& d){
13
204
    puts("useful_F::send_to_arduino()");
14
204
    return TEST_DATA::return_send_to_arduino;
15
204
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/iDomSaveState/idom_save_state.cpp
Line
Count
Source
1
#include <iostream>     // std::cout
2
#include <fstream>
3
#include "idom_save_state.h"
4
#include "../iDom_server_OOP.h"
5
6
iDom_SAVE_STATE::iDom_SAVE_STATE(const std::string &path): m_path(path)
7
208
{
8
208
#ifdef BT_TEST
9
208
    puts("iDom_SAVE_STATE::iDom_SAVE_STATE()");
10
208
#endif
11
208
}
12
13
iDom_SAVE_STATE::~iDom_SAVE_STATE()
14
208
{
15
208
#ifdef BT_TEST
16
208
    puts("iDom_SAVE_STATE::~iDom_SAVE_STATE()");
17
208
#endif
18
208
}
19
20
nlohmann::json iDom_SAVE_STATE::read()
21
12
{
22
12
    std::lock_guard<std::mutex> lGuard(m_mutex);
23
12
    // read a JSON file
24
12
    std::ifstream i(m_path);
25
12
    nlohmann::json j;
26
12
    i >> j;
27
12
28
12
    log_file_mutex.mutex_lock();
29
12
    log_file_cout << INFO << "czytam zapisany stan parametrow iDom" << std::endl;
30
12
    log_file_mutex.mutex_unlock();
31
12
32
12
    return j;
33
12
}
34
35
void iDom_SAVE_STATE::write(const nlohmann::json &jj)
36
200
{
37
200
    std::lock_guard<std::mutex> lGuard(m_mutex);
38
200
    // write prettified JSON to another file
39
200
    std::ofstream o(m_path);
40
200
    o << std::setw(4) << jj << std::endl;
41
200
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/iDomSaveState/test/iDomSaveState_BT.cpp
Line
Count
Source
1
#include <gtest/gtest.h>
2
3
#include "test_data.h"
4
#include "../idom_save_state.h"
5
#include "json.hpp"
6
7
TEST(iDomSaveState, write_and_read)
8
4
{
9
4
    iDom_SAVE_STATE test_saveState("/mnt/ramdisk/iDomStateTest.save");
10
4
    nlohmann::json test_json ;
11
4
12
4
    test_json["happy"] = true;
13
4
    test_json["pi"] = 3.14;
14
4
15
4
    nlohmann::json test_json_in_json;
16
4
    test_json_in_json["name"] = "cyniu";
17
4
    test_json_in_json["age"] = 30;
18
4
19
4
    test_json["person"] = test_json_in_json;
20
4
21
4
    test_saveState.write(test_json);
22
4
    nlohmann::json test_json2 = test_saveState.read();
23
8
    EXPECT_DOUBLE_EQ(test_json.at("pi").get<double>(),
24
8
                     test_json2.at("pi").get<double>()) << "wartosci pi nie sa rowne";
25
4
26
8
    EXPECT_TRUE(test_json2.at("happy").get<bool>()) << " nie jest happy";
27
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/iDomStatus/idomstatus.cpp
Line
Count
Source
1
#include "idomstatus.h"
2
3
iDomSTATUS::iDomSTATUS()
4
808
{
5
808
}
6
7
void iDomSTATUS::addObject(std::string name, STATE st)
8
4.80k
{
9
4.80k
    std::lock_guard < std::mutex > lock ( m_lockGuard);
10
4.80k
    m_stateMAP.insert(std::make_pair(name,st));
11
4.80k
}
12
13
void iDomSTATUS::setObjectState(const std::string& name, STATE st)
14
420
{
15
420
    std::lock_guard < std::mutex > lock ( m_lockGuard);
16
420
    auto i = m_stateMAP.find(name);
17
420
    if (i != m_stateMAP.end()){
18
324
        i->second = st;
19
324
    }
20
96
    else
21
96
    {
22
96
        lock.~lock_guard();
23
96
        addObject(name,st);
24
96
    }
25
420
}
26
27
STATE iDomSTATUS::getObjectState(const std::string& name)
28
312
{
29
312
    std::lock_guard < std::mutex > lock ( m_lockGuard);
30
312
    auto i = m_stateMAP.find(name);
31
312
    if (i != m_stateMAP.end())
32
276
    {
33
276
        return i->second;
34
276
    }
35
36
    return STATE::UNKNOWN;
36
36
}
37
38
std::string iDomSTATUS::getObjectStateString(const std::string& name)
39
600
{
40
600
    std::lock_guard < std::mutex > lock ( m_lockGuard);
41
600
    auto i = m_stateMAP.find(name);
42
600
    if (i != m_stateMAP.end())
43
440
    {
44
440
        return stateToString( i->second);
45
440
    }
46
160
    return stateToString(STATE::UNKNOWN) + " "+name;
47
160
}
48
49
std::string iDomSTATUS::getAllObjectsStateString()
50
12
{
51
12
    std::stringstream st;
52
12
    st << "state: ";
53
12
    std::lock_guard < std::mutex > lock( m_lockGuard);
54
12
    for (auto elm : m_stateMAP)
55
80
    {
56
80
        st << elm.first << "=";
57
80
        st << stateToString(elm.second) << " ";
58
80
    }
59
12
    return st.str();
60
12
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/iDomTools/idomtools.cpp
Line
Count
Source (jump to first uncovered line)
1
#include <algorithm>
2
#include <fstream>
3
#include <string>
4
#include <typeinfo>
5
6
#include "idomtools.h"
7
#include "../functions/functions.h"
8
#include "../../libs/emoji/emoji.h"
9
#include "../../libs/Statistic/statistic.h"
10
#include "../CRON/cron.hpp"
11
#include "../RADIO_433_eq/radio_433_eq.h"
12
#include "json.hpp"
13
#include "../thread_functions/iDom_thread.h"
14
15
iDomTOOLS::iDomTOOLS(thread_data *myData): key(myData->server_settings->TS_KEY)
16
784
{
17
784
    puts("iDomTOOLS::iDomTOOLS()");
18
784
    my_data = myData;
19
784
20
784
    //////////////////////////////////// temeprature /////////////////
21
784
22
784
    allThermometer.add("inside");
23
784
    allThermometer.add("outside");
24
784
    allThermometerUpdate.add("inside");
25
784
    allThermometerUpdate.add("outside");
26
784
    /////////////////////////////////////////////////////////////////
27
#ifndef BT_TEST
28
    pinMode(iDomConst::GPIO_SPIK, OUTPUT); // gpio pin do zasilania glosnikow
29
    digitalWrite(iDomConst::GPIO_SPIK,LOW);
30
    pinMode(iDomConst::GPIO_PRINTER,OUTPUT); /// gpio pin do zsilania drukarki
31
    digitalWrite(iDomConst::GPIO_PRINTER,LOW);
32
#endif
33
    my_data->main_iDomStatus->addObject("cameraLED",STATE::UNKNOWN);
34
784
    my_data->main_iDomStatus->addObject("printer",STATE::OFF);
35
784
    my_data->main_iDomStatus->addObject("speakers",STATE::OFF);
36
784
    my_data->main_iDomStatus->addObject("alarm",STATE::DEACTIVE);
37
784
    my_data->main_iDomStatus->addObject("KODI",STATE::DEACTIVE);
38
784
39
784
    ///////// setup viber api
40
784
    m_viber.setAvatar(my_data->server_settings->viberAvatar);
41
784
    m_viber.setAccessToken(my_data->server_settings->viberToken);
42
784
    m_viber.setURL("https://chatapi.viber.com/pa/send_message");
43
784
    ///////// setup faceboook api
44
784
    m_facebook.setAccessToken(my_data->server_settings->facebookAccessToken);
45
784
46
784
    //////// button 433MHz
47
784
    buttonPointerVector = my_data->main_REC->getButtonPointerVector();
48
784
49
784
    lastButton433MHzLockUnlockTime = Clock::getTime() + Clock(23,58);
50
784
}
51
52
TEMPERATURE_STATE iDomTOOLS::hasTemperatureChange(const std::string& thermometerName, double reference, double histereza )
53
64
{
54
64
    reference += 0.0055;
55
64
    const auto newTemp = allThermometer.getTemp(thermometerName);
56
64
    const auto oldTemp = allThermometer.getOldTemp(thermometerName);
57
64
    const auto lastState = allThermometer.getLastState(thermometerName);
58
64
    if (newTemp >= reference + histereza &&
59
64
            oldTemp < reference + histereza &&
60
64
            lastState != TEMPERATURE_STATE::Over)
61
12
    {
62
12
        my_data->myEventHandler.run("test")->addEvent("over: new "+ to_string_with_precision(newTemp)+" old: "
63
12
                                                      +to_string_with_precision(oldTemp)+" ref: "
64
12
                                                      +to_string_with_precision(reference));
65
12
        allThermometer.setState(thermometerName, TEMPERATURE_STATE::Over);
66
12
        return TEMPERATURE_STATE::Over;
67
12
    }
68
52
    else if (newTemp <= reference - histereza &&
69
52
             oldTemp > reference - histereza &&
70
52
             lastState != TEMPERATURE_STATE::Under)
71
12
    {
72
12
        my_data->myEventHandler.run("test")->addEvent("under: new "+to_string_with_precision(newTemp)+" old: "
73
12
                                                      +to_string_with_precision(oldTemp)+" ref: "
74
12
                                                      +to_string_with_precision(reference));
75
12
        allThermometer.setState(thermometerName, TEMPERATURE_STATE::Under);
76
12
        return TEMPERATURE_STATE::Under;
77
12
    }
78
40
79
40
    my_data->myEventHandler.run("test")->addEvent("noChanges: new "+to_string_with_precision(newTemp)+" old: "
80
40
                                                  +to_string_with_precision(oldTemp)+" ref: "+to_string_with_precision(reference));
81
40
82
40
    allThermometer.setState(thermometerName, TEMPERATURE_STATE::NoChanges);
83
40
    return TEMPERATURE_STATE::NoChanges;
84
40
}
85
86
void iDomTOOLS::sendSMSifTempChanged(const std::string& thermomethernName, int reference)
87
64
{
88
64
    TEMPERATURE_STATE status = hasTemperatureChange(thermomethernName,reference,0.5);
89
64
    std::string m = "temperature "+thermomethernName+" over "+ EMOJI::emoji(E_emoji::NORTH_EAST_ARROW)
90
64
            + to_string_with_precision(reference);
91
64
92
64
    if (status == TEMPERATURE_STATE::Over)
93
12
    {
94
12
        my_data->myEventHandler.run("temperature")->addEvent(m);
95
12
        if (reference < 2)
96
4
        {
97
4
            sendViberMsg(m,my_data->server_settings->viberReceiver.at(0),my_data->server_settings->viberSender);
98
4
            sendViberMsg(m,my_data->server_settings->viberReceiver.at(1),my_data->server_settings->viberSender);
99
4
        }
100
8
        else
101
8
        {
102
8
            sendViberMsg(m,my_data->server_settings->viberReceiver.at(0),my_data->server_settings->viberSender);
103
8
        }
104
12
    }
105
52
    else if (status == TEMPERATURE_STATE::Under)
106
12
    {
107
12
        m ="temperature " + thermomethernName+" under "+EMOJI::emoji(E_emoji::SOUTH_EAST_ARROW)
108
12
                +to_string_with_precision(reference);
109
12
        my_data->myEventHandler.run("temperature")->addEvent(m);
110
12
        if (reference < 2)
111
8
        {
112
8
            sendViberPicture(m,"http://canacopegdl.com/images/cold/cold-14.jpg",
113
8
                             my_data->server_settings->viberReceiver.at(0),
114
8
                             my_data->server_settings->viberSender);
115
8
            sendViberPicture(m,"http://canacopegdl.com/images/cold/cold-14.jpg",
116
8
                             my_data->server_settings->viberReceiver.at(1),
117
8
                             my_data->server_settings->viberSender);
118
8
            postOnFacebook(m,"http://canacopegdl.com/images/cold/cold-14.jpg");
119
8
        }
120
4
        else {
121
4
            sendViberMsg(m,my_data->server_settings->viberReceiver.at(0),
122
4
                         my_data->server_settings->viberSender);
123
4
        }
124
12
    }
125
40
    else{
126
40
        //my_data->myEventHandler.run("unknown")->addEvent("temperatura nie przeszla przez "+to_string_with_precision(reference));
127
40
    }
128
64
}
129
130
std::string iDomTOOLS::getThermoStats(const std::string& name)
131
8
{
132
8
    return allThermometerUpdate.getStatsByName(name);
133
8
}
134
135
void iDomTOOLS::updateTemperatureStats()
136
24
{
137
24
    auto v = getTemperature();
138
24
    allThermometerUpdate.updateAll(&v);
139
24
    allThermometerUpdate.updateStats("outside");
140
24
    allThermometerUpdate.updateStats("inside");
141
24
142
24
    if( true == allThermometerUpdate.isMoreDiff("outside",2.1))
143
8
    {
144
8
        auto data = allThermometerUpdate.getLast2("outside");
145
8
        std::string msg = "alarm roznicy temeratur na polu! " + to_string_with_precision(data.first) +" na "+
146
8
                to_string_with_precision(data.second);
147
8
148
8
        if (data.first > data.second)
149
4
        {
150
4
            msg += " temperatura maleje " + EMOJI::emoji(E_emoji::CHART_WITH_DOWNWARDS_TREND);
151
4
        }
152
4
        else
153
4
        {
154
4
            msg += " temperatura rośnie " + EMOJI::emoji(E_emoji::CHART_WITH_UPWARDS_TREND);
155
4
        }
156
8
157
8
        sendViberMsg(msg,
158
8
                     my_data->server_settings->viberReceiver.at(0),
159
8
                     my_data->server_settings->viberSender);
160
8
161
8
        log_file_mutex.mutex_lock();
162
8
        log_file_cout << WARNING << msg << std::endl;
163
8
        log_file_mutex.mutex_unlock();
164
8
    }
165
24
    if( true == allThermometerUpdate.isMoreDiff("inside",2.1))
166
8
    {
167
8
        auto data = allThermometerUpdate.getLast2("inside");
168
8
        std::string msg = "alarm roznicy temeratur na mieszkaniu! " + to_string_with_precision(data.first) +" na "+
169
8
                to_string_with_precision(data.second);
170
8
171
8
        if (data.first > data.second)
172
4
        {
173
4
            msg += " temperatura maleje " + EMOJI::emoji(E_emoji::CHART_WITH_DOWNWARDS_TREND);
174
4
        }
175
4
        else
176
4
        {
177
4
            msg += " temperatura rośnie " + EMOJI::emoji(E_emoji::CHART_WITH_UPWARDS_TREND);
178
4
        }
179
8
180
8
        sendViberMsg(msg,
181
8
                     my_data->server_settings->viberReceiver.at(0),
182
8
                     my_data->server_settings->viberSender);
183
8
184
8
        log_file_mutex.mutex_lock();
185
8
        log_file_cout << WARNING << msg << std::endl;
186
8
        log_file_mutex.mutex_unlock();
187
8
    }
188
24
}
189
190
void iDomTOOLS::turnOnSpeakers()
191
32
{
192
32
    if (useful_F::myStaticData->idom_all_state.houseState == STATE::UNLOCK)
193
16
    {
194
16
        digitalWrite(iDomConst::GPIO_SPIK, HIGH);
195
16
        useful_F::myStaticData->main_iDomStatus->setObjectState("speakers",STATE::ON);
196
16
    }
197
16
    else
198
16
    {
199
16
        useful_F::myStaticData->myEventHandler.run("speakers")->addEvent("speakers can not start due to home state: "+
200
16
                                                                         stateToString(useful_F::myStaticData->idom_all_state.houseState));
201
16
    }
202
32
    useful_F::myStaticData->main_iDomTools->saveState_iDom();
203
32
}
204
205
void iDomTOOLS::turnOffSpeakers()
206
24
{
207
24
    digitalWrite(iDomConst::GPIO_SPIK, LOW);
208
24
    useful_F::myStaticData->main_iDomStatus->setObjectState("speakers",STATE::OFF);
209
24
    // useful_F::myStaticData->main_iDomTools->saveState_iDom();
210
24
}
211
212
void iDomTOOLS::turnOnPrinter()
213
20
{
214
20
    if (my_data->idom_all_state.houseState == STATE::UNLOCK)
215
16
    {
216
16
        digitalWrite(iDomConst::GPIO_PRINTER,HIGH);
217
16
        my_data->myEventHandler.run("230V")->addEvent("230v drukarki ON");
218
16
        my_data->main_iDomStatus->setObjectState("printer",STATE::ON);
219
16
    }
220
4
    else{
221
4
        my_data->myEventHandler.run("230V")->addEvent("Printer can not start due to home state: "+
222
4
                                                      stateToString(my_data->idom_all_state.houseState));
223
4
    }
224
20
}
225
226
void iDomTOOLS::turnOffPrinter()
227
24
{
228
24
    digitalWrite(iDomConst::GPIO_PRINTER,LOW);
229
24
    my_data->myEventHandler.run("230V")->addEvent("230v drukarki OFF");
230
24
    my_data->main_iDomStatus->setObjectState("printer",STATE::OFF);
231
24
}
232
233
PIN_STATE iDomTOOLS::getPinState(int pin_number)
234
28
{
235
28
    int pin_state = digitalRead(pin_number);
236
28
    switch (pin_state){
237
28
    case 0:
238
12
        return PIN_STATE::LOW_STATE;
239
28
    case 1:
240
8
        return PIN_STATE::HIGH_STATE;
241
28
    default:
242
8
        return PIN_STATE::UNKNOWN_STATE;
243
0
    }
244
0
}
245
246
void iDomTOOLS::turnOnOffPrinter()
247
16
{
248
16
    PIN_STATE pinState = getPinState(iDomConst::GPIO_PRINTER);
249
16
    switch (pinState){
250
16
    case PIN_STATE::HIGH_STATE:
251
4
        turnOffPrinter();
252
4
        my_data->mainLCD->set_lcd_STATE(10);
253
4
        my_data->mainLCD->printString(true,0,0,"230V OFF");
254
4
        break;
255
16
    case PIN_STATE::LOW_STATE:
256
8
        turnOnPrinter();
257
8
        my_data->mainLCD->set_lcd_STATE(10);
258
8
        my_data->mainLCD->printString(true,0,0,"230V ON");
259
8
        break;
260
16
    default:
261
4
        puts("def");
262
4
263
4
        log_file_mutex.mutex_lock();
264
4
        log_file_cout << CRITICAL << " blad odczytu stanu pinu zasilania drukarki "<< std::endl;
265
4
        log_file_mutex.mutex_unlock();
266
16
    }
267
16
}
268
269
void iDomTOOLS::turnOnOff433MHzSwitch(const std::string& name)
270
20
{
271
20
    STATE listwaState = my_data->main_iDomStatus->getObjectState(name);
272
20
    RADIO_SWITCH *m_switch = nullptr;
273
20
    try {
274
20
        m_switch = dynamic_cast<RADIO_SWITCH*>(my_data->main_REC->getEqPointer(name));
275
20
    } catch (const std::string& e) {
276
4
        log_file_mutex.mutex_lock();
277
4
        log_file_cout << CRITICAL << " void iDomTOOLS::turnOnOff433MHzSwitch(const std::string& name) "<< e << std::endl;
278
4
        log_file_mutex.mutex_unlock();
279
4
        return;
280
4
    }
281
16
282
16
    if (listwaState == STATE::ON){
283
8
        my_data->mainLCD->set_lcd_STATE(10);
284
8
        my_data->mainLCD->printString(true,0,0,"230V OFF "+name);
285
8
        m_switch->off();
286
8
    }
287
8
    else if (listwaState == STATE::OFF){
288
8
        my_data->mainLCD->set_lcd_STATE(10);
289
8
        my_data->mainLCD->printString(true,0,0,"230V ON "+name);
290
8
        m_switch->on();
291
8
    }
292
16
    saveState_iDom();
293
16
}
294
295
void iDomTOOLS::turnOn433MHzSwitch(std::string name)
296
12
{
297
12
    try {
298
12
        RADIO_SWITCH *m_switch = dynamic_cast<RADIO_SWITCH*>(my_data->main_REC->getEqPointer(std::move(name)));
299
12
        m_switch->on();
300
12
    } catch (const std::string& e) {
301
4
        log_file_mutex.mutex_lock();
302
4
        log_file_cout << CRITICAL << " void iDomTOOLS::turnOn433MHzSwitch(std::string name) "<< e << std::endl;
303
4
        log_file_mutex.mutex_unlock();
304
4
    }
305
12
}
306
307
void iDomTOOLS::turnOff433MHzSwitch(std::string name)
308
20
{
309
20
    try {
310
20
        RADIO_SWITCH *m_switch = dynamic_cast<RADIO_SWITCH*>(my_data->main_REC->getEqPointer(std::move(name)));
311
20
        m_switch->off();
312
20
    } catch (const std::string& e) {
313
4
        log_file_mutex.mutex_lock();
314
4
        log_file_cout << CRITICAL << " void iDomTOOLS::turnOff433MHzSwitch(std::string name) "<< e << std::endl;
315
4
        log_file_mutex.mutex_unlock();
316
4
    }
317
20
}
318
319
void iDomTOOLS::runOnSunset()
320
12
{
321
12
    if (my_data->idom_all_state.houseState == STATE::UNLOCK)
322
8
    {
323
8
        ////switch 433mhz
324
40
        for (auto m_switch : my_data->main_REC->getSwitchPointerVector()){
325
40
            m_switch->onSunset();
326
40
        }
327
8
    }
328
4
    else{
329
4
        my_data->myEventHandler.run("iDom")->addEvent("433MHz can not start due to home state: "+
330
4
                                                      stateToString(my_data->idom_all_state.houseState));
331
4
    }
332
12
}
333
334
void iDomTOOLS::runOnSunrise()
335
16
{
336
16
    if (my_data->idom_all_state.houseState == STATE::UNLOCK)
337
8
    {
338
8
        ////switch 433mhz
339
40
        for (auto m_switch : my_data->main_REC->getSwitchPointerVector()){
340
40
            m_switch->onSunrise();
341
40
        }
342
8
    }
343
8
    else{
344
8
        my_data->myEventHandler.run("iDom")->addEvent("433MHz can not start due to home state: "+
345
8
                                                      stateToString(my_data->idom_all_state.houseState));
346
8
    }
347
16
    my_data->main_iDomTools->ledOFF();
348
16
}
349
350
void iDomTOOLS::lockHome()
351
28
{
352
28
    my_data->idom_all_state.houseState = STATE::LOCK;
353
28
    my_data->main_iDomStatus->setObjectState("house", STATE::LOCK);
354
28
    my_data->main_iDomTools->sendViberPicture("dom zablokownay!",
355
28
                                              "http://cyniu88.no-ip.pl/images/iDom/iDom/lock.jpg",
356
28
                                              my_data->server_settings->viberReceiver.at(0),
357
28
                                              my_data->server_settings->viberSender);
358
28
359
28
    log_file_mutex.mutex_lock();
360
28
    log_file_cout << INFO << "status domu - "+stateToString(my_data->idom_all_state.houseState)<< std::endl;
361
28
    log_file_mutex.mutex_unlock();
362
28
363
28
    saveState_iDom();
364
28
}
365
366
void iDomTOOLS::unlockHome()
367
56
{
368
56
    my_data->idom_all_state.houseState = STATE::UNLOCK;
369
56
    my_data->main_iDomStatus->setObjectState("house", STATE::UNLOCK);
370
56
    my_data->main_iDomTools->sendViberPicture("dom odblokownay!",
371
56
                                              "http://cyniu88.no-ip.pl/images/iDom/iDom/unlock.jpg",
372
56
                                              my_data->server_settings->viberReceiver.at(0),
373
56
                                              my_data->server_settings->viberSender);
374
56
375
56
    log_file_mutex.mutex_lock();
376
56
    log_file_cout << INFO << "status domu - "+stateToString(my_data->idom_all_state.houseState)<< std::endl;
377
56
    log_file_mutex.mutex_unlock();
378
56
379
56
    saveState_iDom();
380
56
}
381
382
void iDomTOOLS::switchActionOnLockHome()
383
4
{
384
4
    ////switch 433mhz
385
20
    for (auto m_switch : my_data->main_REC->getSwitchPointerVector()){
386
20
        m_switch->onLockHome();
387
20
    }
388
4
}
389
390
void iDomTOOLS::switchActionOnUnlockHome()
391
4
{
392
4
    ////switch 433mhz
393
20
    for (auto m_switch : my_data->main_REC->getSwitchPointerVector()){
394
20
        m_switch->onUnlockHome();
395
20
    }
396
4
}
397
398
std::string iDomTOOLS::buttonPressed(const std::string& id)
399
8
{
400
8
    for (auto n : buttonPointerVector){
401
8
        if (id == n->getID()){
402
4
            return n->getName();
403
4
        }
404
4
    }
405
4
    throw "UNKNOWN BUTTON ID: " + std::to_string(id);
406
4
}
407
408
void iDomTOOLS::button433MHzPressedAction(const std::string& name)
409
16
{
410
16
    if (name == "locker"){
411
16
        RADIO_BUTTON* buttonLocker = static_cast<RADIO_BUTTON*>(my_data->main_REC->getEqPointer(name) );
412
16
        button433mhzLockerPressed(buttonLocker);
413
16
    }
414
16
}
415
416
void iDomTOOLS::button433mhzLockerPressed(RADIO_BUTTON *radioButton)
417
40
{
418
40
    static unsigned int counter = 0;
419
40
420
40
    Clock t = Clock::getTime();
421
40
    if (lastButton433MHzLockUnlockTime != t /*|| (lastButton433MHzLockUnlockTime + Clock(0,1)) == t*/)
422
24
    {
423
24
#ifdef BT_TEST
424
24
        std::cout << "LOCKER TEST iDomTOOLS::button433mhzLockerPressed()" <<std::endl;
425
24
#endif
426
24
        lastButton433MHzLockUnlockTime = t;
427
24
        counter = 0;
428
24
        if(my_data->idom_all_state.houseState != STATE::UNLOCK)
429
8
        {
430
8
            buttonUnlockHome();
431
8
            puts("\nodblokuje dom\n");
432
8
            radioButton->setState(STATE::UNLOCK);
433
8
        }
434
16
        else if (my_data->main_iDomStatus->getObjectState("music") == STATE::PLAY)
435
4
        {
436
4
            ledOFF();
437
4
            MPD_stop();
438
4
            turnOffPrinter();
439
4
            radioButton->setState(STATE::STOP);
440
4
            switchActionOnLockHome();
441
4
            //TODO dodać wylaczanie wiatraka
442
4
        }
443
12
        else if (my_data->main_iDomStatus->getObjectState("music") == STATE::STOP)
444
4
        {
445
4
            MPD_play(my_data);
446
4
            switchActionOnUnlockHome();
447
4
            if(isItDay() == false)
448
4
            {
449
4
                ledOn(my_data->ptr_pilot_led->colorLED[2]);
450
4
            }
451
4
            radioButton->setState(STATE::PLAY);
452
4
        }
453
24
    }
454
16
    else
455
16
    {
456
16
        ++counter;
457
16
        if (counter == 2)
458
8
        {
459
8
            buttonLockHome();
460
8
            puts("\nzablokuje dom\n");
461
8
            radioButton->setState(STATE::LOCK);
462
8
        }
463
16
        //#ifdef BT_TEST
464
16
        std::cout << "LOCKER TEST iDomTOOLS::button433mhzLockerPressed()- counter: "<<counter <<std::endl;
465
16
        //#endif
466
16
    }
467
40
468
40
}
469
470
void iDomTOOLS::buttonLockHome()
471
8
{
472
8
    ledOFF();
473
8
    MPD_stop();
474
8
    turnOffPrinter();
475
8
    lockHome();
476
8
}
477
478
void iDomTOOLS::buttonUnlockHome()
479
8
{
480
8
    unlockHome();
481
8
    MPD_play(my_data);
482
8
    if(isItDay() == false){
483
8
        ledOn(my_data->ptr_pilot_led->colorLED[2]);
484
8
    }
485
8
}
486
487
bool iDomTOOLS::isItDay()
488
60
{
489
60
    Clock now = Clock::getTime();
490
60
    if(now < iDomTOOLS::getSunriseClock() || now > iDomTOOLS::getSunsetClock()){
491
56
        return false;
492
56
    }
493
4
    return true;
494
4
}
495
496
std::string iDomTOOLS::getAllDataSunrisesunset()
497
4
{
498
4
    return sun.getAllData();
499
4
}
500
501
CARDINAL_DIRECTIONS::ALARM_INFO iDomTOOLS::getLightningStruct()
502
16
{
503
16
    std::lock_guard<std::mutex> lock(m_lightningMutex);
504
16
    return m_lightningStruct;
505
16
}
506
507
void iDomTOOLS::setLightningStruct(CARDINAL_DIRECTIONS::ALARM_INFO &s)
508
8
{
509
8
    std::lock_guard<std::mutex> lock(m_lightningMutex);
510
8
    //std::cout <<"struktura setowana " << s.data.str() <<std::endl;
511
8
    m_lightningStruct = s;
512
8
513
8
    //std::cout <<"struktura już po setowaniu " << m_lightningStruct.data.str() <<std::endl;
514
8
}
515
516
void iDomTOOLS::checkLightning()
517
4
{
518
4
    nlohmann::json jj = useful_F_libs::getJson(my_data->server_settings->lightningApiURL);
519
4
520
4
    CARDINAL_DIRECTIONS::ALARM_INFO lightningData = lightning.lightningAlert(jj);
521
4
    setLightningStruct(lightningData);
522
4
    bool result = lightning.checkLightningAlert(&lightningData);
523
4
524
4
    if(result == true)
525
4
    {
526
4
527
4
        m_viber.setAvatar("http://cyniu88.no-ip.pl/avatar/lightning.jpg");
528
4
        STATE stateMSG = sendViberMsgBool("UWAGA BURZA KOŁO KRAKOWA! "+EMOJI::emoji(E_emoji::THUNDER_CLOUD_AND_RAIN)
529
4
                                          +"\\n\\n "+lightningData.data.str() ,
530
4
                                          my_data->server_settings->viberReceiver.at(0),
531
4
                                          my_data->server_settings->viberSender);
532
4
533
4
        if(stateMSG == STATE::SEND_NOK){
534
4
            log_file_mutex.mutex_lock();
535
4
            log_file_cout << ERROR << "nie wysłano informacje o burzy"<< std::endl;
536
4
            log_file_mutex.mutex_unlock();
537
4
        }
538
4
        stateMSG = sendViberMsgBool("UWAGA BURZA KOŁO KRAKOWA! "+EMOJI::emoji(E_emoji::THUNDER_CLOUD_AND_RAIN)
539
4
                                    +"\\n\\n "+lightningData.data.str() ,
540
4
                                    my_data->server_settings->viberReceiver.at(1),
541
4
                                    my_data->server_settings->viberSender);
542
4
543
4
        m_viber.setAvatar(my_data->server_settings->viberAvatar);
544
4
        if(stateMSG == STATE::SEND_OK)
545
0
        {
546
0
            log_file_mutex.mutex_lock();
547
0
            log_file_cout << INFO << "wysłano informacje o burzy"<< std::endl;
548
0
            log_file_mutex.mutex_unlock();
549
0
        }
550
4
        else
551
4
        {
552
4
            log_file_mutex.mutex_lock();
553
4
            log_file_cout << ERROR << "nie wysłano informacje o burzy"<< std::endl;
554
4
            log_file_mutex.mutex_unlock();
555
4
        }
556
4
    }
557
4
}
558
559
std::string iDomTOOLS::getSunrise(bool extend )
560
28
{
561
28
    Clock tt = sun.getSunRise();
562
28
    if (extend == true){
563
12
        return "Sunrise time: "+tt.getString();
564
12
    }
565
16
    return tt.getString();
566
16
}
567
568
std::string iDomTOOLS::getSunset(bool extend )
569
28
{
570
28
    Clock tt = sun.getSunSet();
571
28
    if (extend == true){
572
12
        return "Sunset time: "+tt.getString();
573
12
    }
574
16
    return tt.getString();
575
16
}
576
577
Clock iDomTOOLS::getSunsetClock()
578
11
{
579
11
    return sun.getSunSet();
580
11
}
581
582
Clock iDomTOOLS::getSunriseClock()
583
60
{
584
60
    return sun.getSunRise();
585
60
}
586
587
std::string iDomTOOLS::getDayLenght(bool extend )
588
28
{
589
28
    Clock tt = sun.getDayLength();
590
28
    if (extend == true){
591
12
        return "Day Lenght : "+tt.getString();
592
12
    }
593
16
    return tt.getString();
594
16
}
595
596
std::string iDomTOOLS::getWeatherEvent(const std::string& city, unsigned int radius)
597
4
{
598
4
    std::string url = "http://burze.dzis.net/ramka.php?miejscowosc=";
599
4
    url.append(city);
600
4
    url.append("&promien=");
601
4
    url.append(std::to_string(radius));
602
4
    return useful_F_libs::httpPost(url, 10);
603
4
}
604
605
std::vector<WEATHER_ALER> iDomTOOLS::getAlert(std::string data)
606
4
{
607
4
    std::vector<WEATHER_ALER> wAlert;
608
4
    WEATHER_ALER tempWA;
609
4
    std::string d = useful_F_libs::removeHtmlTag(data);
610
4
    std::vector<std::string> vect;
611
4
612
4
    vect = useful_F::split(d,'\n');
613
4
    vect.pop_back();
614
4
    for (auto n : vect)
615
28
    {
616
28
        if (n.find("brak") == std::string::npos)
617
4
        {
618
4
            tempWA.alert = n;
619
4
            tempWA.name = n;
620
4
            tempWA.sended = false;
621
4
            wAlert.push_back(tempWA);
622
4
        }
623
28
    }
624
4
    return {wAlert};
625
4
}
626
627
void iDomTOOLS::textToSpeach(std::vector<std::string> *textVector)
628
16
{
629
16
    if (textVector->empty() ){
630
4
        return;
631
4
    }
632
12
    std::string txt;
633
12
634
28
    for (auto a : *textVector){
635
28
        txt += a;
636
28
    }
637
12
    /////////// start thread TTS - python use ////////////////////////
638
12
    std::string command = " python /home/pi/programowanie/iDom_server_OOP/script/PYTHON/gadacz.py \\"+ txt +"\\";
639
12
    if(my_data->ptr_MPD_info->isPlay){
640
4
641
4
    }
642
8
    else {
643
8
        turnOnSpeakers();
644
8
    }
645
12
646
12
    useful_F::runLinuxCommand(command);
647
12
648
12
    if(my_data->ptr_MPD_info->isPlay){
649
4
650
4
    }
651
8
    else {
652
8
        turnOffSpeakers();
653
8
    }
654
12
}
655
656
std::string iDomTOOLS::getTextToSpeach()
657
12
{
658
12
    std::vector<std::string> dayL = useful_F::split(getDayLenght(),':');
659
12
    std::stringstream text;
660
12
    std::string smogText = getSmog();
661
12
    int smogInt = std::stoi(smogText);
662
12
    text << "Godzina: " << Clock::getTime().getString();
663
12
    text << ". \nWschód słońca: " << getSunrise();
664
12
    text << ". \nZachód słońca: " << getSunset();
665
12
    text << ". \nDługość dnia: " << dayL[0] << " godzin " << dayL[1] << " minut";
666
12
    text <<". \n";
667
12
    dayL = getTemperature();
668
12
    text << "Temperatura na zewnątrz: " << dayL[1] << " stopnia. \n";
669
12
    text << "Temperatura w pokoju: " << dayL[0] << " stopnia. \n";
670
12
    text << "Smog: " << smogText << " mg/m^3. \n";
671
12
    if (smogInt > 50){
672
0
        int result = smogInt *2;
673
0
        text << "UWAGA! Maksymalna wartość przekroczona " << result << "%.";
674
0
    }
675
12
    return text.str();
676
12
}
677
678
std::vector<std::string> iDomTOOLS::getTemperature()
679
72
{
680
72
    std::vector<std::string> vect = useful_F::split(useful_F::send_to_arduino(my_data,"temperature:22;"),':');
681
72
    return vect;
682
72
}
683
684
std::string iDomTOOLS::getTemperatureString()
685
8
{
686
8
    return useful_F::send_to_arduino(my_data,"temperature:22;");
687
8
}
688
689
std::string iDomTOOLS::getSmog()
690
56
{
691
56
    CURL *curl;
692
56
    CURLcode res;
693
56
    std::string readBuffer;
694
56
    curl = curl_easy_init();
695
56
696
56
    if(curl) {
697
56
        curl_easy_setopt(curl, CURLOPT_URL, "www.smog.krakow.pl");
698
56
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, useful_F_libs::WriteCallback);
699
56
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
700
56
        res = curl_easy_perform(curl);
701
56
        /* Check for errors */
702
56
        if(res != CURLE_OK)
703
0
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
704
0
                    curl_easy_strerror(res));
705
56
706
56
        /* always cleanup */
707
56
        curl_easy_cleanup(curl);
708
56
    }
709
56
    curl_global_cleanup();
710
56
    int start = readBuffer.find("<h2 class=\"polution\">");
711
56
    try {
712
56
        readBuffer = readBuffer.substr(start, 40);
713
56
    }
714
56
    catch (...){
715
0
        log_file_mutex.mutex_lock();
716
0
        log_file_cout << CRITICAL << "wyjatek substr() e getSmog() !!!!!!"<< std::endl;
717
0
        log_file_mutex.mutex_unlock();
718
0
    }
719
56
720
56
    readBuffer = useful_F_libs::find_tag(readBuffer);
721
56
722
56
    return readBuffer;
723
56
}
724
725
void iDomTOOLS::send_temperature_thingSpeak()
726
32
{
727
32
    std::vector<std::string> _temperature = getTemperature();
728
32
    std::string addres = "api.thingspeak.com/update?key=";
729
32
    addres+=key;
730
32
    addres+="&field1=";
731
32
    addres+= _temperature.at(0);
732
32
    // addres.erase(addres.size()-2,addres.size());
733
32
    addres+= "&field3="+_temperature.at(1);
734
32
    addres+="&field2="+getSmog();
735
32
    //////////////////////////////// pozyskanie temperatury
736
32
    allThermometer.updateAll(&_temperature);
737
32
    sendSMSifTempChanged("outside",0);
738
32
    sendSMSifTempChanged("inside",24);
739
32
    std::string s = useful_F_libs::httpPost(addres,10);
740
32
741
32
    if(s == "0"){
742
0
        log_file_mutex.mutex_lock();
743
0
        log_file_cout << CRITICAL << " błąd wysyłania temoeratury na thingspeak: "<< s << std::endl;
744
0
        log_file_mutex.mutex_unlock();
745
0
    }
746
32
}
747
748
void iDomTOOLS::cameraLedON(const std::string& link)
749
12
{
750
12
    Clock t = Clock::getTime();
751
12
    SunRiseSet sun;
752
12
    Clock sunRise, sunSet;
753
12
    sunRise = sun.getSunRise();
754
12
    sunSet = sun.getSunSet();
755
12
    sunSet += Clock(23,30); // +23:30 == -00:30
756
12
    if (t <= sunRise || t >= sunSet){
757
8
        //printf("zapalam leda!\n");
758
8
        std::string s = useful_F_libs::httpPost(link,10);
759
8
        if (s == "ok.\n"){
760
8
            my_data->main_iDomStatus->setObjectState("cameraLED",STATE::ON);
761
8
            // printf("w ifie\n");
762
8
        }
763
8
    }
764
12
    // printf("nie odpalam leda!\n");
765
12
}
766
767
void iDomTOOLS::cameraLedOFF(const std::string& link)
768
12
{
769
12
    std::string s = useful_F_libs::httpPost(link,10);
770
12
    //printf (" camera response '%s' \n", s.c_str());
771
12
    if (s == "ok.\n"){
772
12
        my_data->main_iDomStatus->setObjectState("cameraLED",STATE::OFF);
773
12
        //printf("w ifie\n");
774
12
    }
775
12
}
776
777
nlohmann::json iDomTOOLS::sendViberMsg(const std::string &msg,
778
                                       const std::string &receiver,
779
                                       const std::string &senderName,
780
                                       const std::string& accessToken,
781
                                       const std::string& url)
782
44
{
783
44
    nlohmann::json jj;
784
44
    std::lock_guard<std::mutex> lock(m_msgMutex);
785
44
    jj = nlohmann::json::parse( m_viber.sendViberMSG(msg,receiver,senderName,accessToken,url));
786
44
    return jj;
787
44
}
788
789
nlohmann::json iDomTOOLS::sendViberPicture(const std::string &msg,
790
                                           const std::string &image,
791
                                           const std::string &receiver,
792
                                           const std::string &senderName,
793
                                           const std::string& accessToken,
794
                                           const std::string& url)
795
100
{
796
100
    nlohmann::json jj;
797
100
    std::lock_guard<std::mutex> lock(m_msgMutex);
798
100
    jj = nlohmann::json::parse(m_viber.sendViberPicture(msg,image,receiver,senderName,accessToken,url));
799
100
    return jj;
800
100
}
801
802
STATE iDomTOOLS::sendViberMsgBool(const std::string &msg,
803
                                  const std::string &receiver,
804
                                  const std::string &senderName,
805
                                  const std::string& accessToken,
806
                                  const std::string& url)
807
8
{
808
8
    nlohmann::json jj = sendViberMsg(msg,receiver,senderName,accessToken,url);
809
8
    STATE ret = STATE::SEND_NOK;
810
8
    if(jj.find("status_message")!= jj.end())
811
0
    {
812
0
        if(jj.at("status_message").get<std::string>() == "ok")
813
0
        {
814
0
            ret = STATE::SEND_OK;
815
0
        }
816
0
    }
817
8
    else
818
8
    {
819
8
        log_file_mutex.mutex_lock();
820
8
        log_file_cout << ERROR << "nie wyslanno wiadomosci viber"<< jj.dump()<< std::endl;
821
8
        log_file_mutex.mutex_unlock();
822
8
    }
823
8
    return ret;
824
8
}
825
826
STATE iDomTOOLS::sendViberPictureBool(const std::string& msg,
827
                                      const std::string& image,
828
                                      const std::string& receiver,
829
                                      const std::string& senderName,
830
                                      const std::string& accessToken,
831
                                      const std::string& url)
832
0
{
833
0
    nlohmann::json jj = sendViberPicture(msg,image,receiver,senderName,accessToken,url);
834
0
    STATE ret = STATE::SEND_NOK;
835
0
    if(jj.at("status_message").get<std::string>() == "ok")
836
0
    {
837
0
        ret = STATE::SEND_OK;
838
0
    }
839
0
    else
840
0
    {
841
0
        log_file_mutex.mutex_lock();
842
0
        log_file_cout << ERROR << "nie wyslanno wiadomosci viber"<< jj.dump()<< std::endl;
843
0
        log_file_mutex.mutex_unlock();
844
0
    }
845
0
    return ret;
846
0
}
847
848
std::string iDomTOOLS::postOnFacebook(const std::string& msg, const std::string& image)
849
8
{
850
8
    std::lock_guard<std::mutex> lock(m_msgMutex);
851
8
    if (image != "NULL"){
852
8
        return m_facebook.postPhotoOnWall(image,msg);
853
8
    }
854
0
855
0
    return m_facebook.postTxtOnWall(msg);
856
0
}
857
858
std::string iDomTOOLS::ledOFF()
859
48
{
860
48
    return useful_F::send_to_arduino(my_data,"LED_STOP:2;");
861
48
}
862
863
std::string iDomTOOLS::ledClear()
864
4
{
865
4
    return useful_F::send_to_arduino(my_data,"LED_CLEAR:2;");
866
4
}
867
868
std::string iDomTOOLS::ledClear(unsigned int from, unsigned int to)
869
52
{
870
52
    LED_Strip ledColor(0,60,0,0,0,"BLACK");
871
52
    useful_F::send_to_arduino(my_data,ledColor.get(from, to));
872
52
    return "Led cleared";
873
52
}
874
875
std::string iDomTOOLS::ledOn(const LED_Strip& ledColor, unsigned int from, unsigned int to)
876
84
{
877
84
    if (my_data->idom_all_state.houseState == STATE::UNLOCK)
878
12
    {
879
12
        return useful_F::send_to_arduino(my_data,ledColor.get(from, to));
880
12
    }
881
72
    else{
882
72
        my_data->myEventHandler.run("LED")->addEvent("LED can not start due to home state: "+
883
72
                                                     stateToString(my_data->idom_all_state.houseState));
884
72
    }
885
84
    return "iDom LOCKED!";
886
84
}
887
888
void iDomTOOLS::checkAlarm()
889
40
{
890
40
    unsigned int fromVol = my_data->alarmTime.fromVolume;
891
40
    unsigned int toVol   = my_data->alarmTime.toVolume;
892
40
    unsigned int radioId = my_data->alarmTime.radioID;
893
40
894
40
    Clock now = Clock::getTime();
895
40
    if (now == my_data->alarmTime.time && my_data->alarmTime.state == STATE::ACTIVE){
896
4
        my_data->alarmTime.state = STATE::WORKING;
897
4
        MPD_volumeSet(my_data, fromVol);
898
4
        MPD_play(my_data,radioId);
899
4
        my_data->main_iDomStatus->setObjectState("alarm",STATE::DEACTIVE);
900
4
    }
901
40
902
40
    if (my_data->alarmTime.state == STATE::WORKING){
903
40
        unsigned int vol = MPD_getVolume(my_data) + 1;
904
40
        if (vol < toVol){
905
36
            MPD_volumeSet(my_data, vol);
906
36
907
36
            if(iDomTOOLS::isItDay() == false){
908
36
                my_data->main_iDomTools->ledOn(my_data->ptr_pilot_led->colorLED[2],fromVol,vol);
909
36
            }
910
36
        }
911
4
        else{
912
4
            my_data->alarmTime.state = STATE::DEACTIVE;
913
4
            if(iDomTOOLS::isItDay() == false){
914
4
                 my_data->main_iDomTools->turnOn433MHzSwitch("ALARM");
915
4
                 saveState_iDom();
916
4
                 log_file_mutex.mutex_lock();
917
4
                 log_file_cout << DEBUG << "uruchamiam ALARM 433MHz"<< std::endl;
918
4
                 log_file_mutex.mutex_unlock();
919
4
            }
920
4
        }
921
40
    }
922
40
}
923
924
void iDomTOOLS::saveState_iDom()
925
196
{
926
196
    iDom_SAVE_STATE info(my_data->server_settings->saveFilePath);
927
196
    nlohmann::json jsonAlarm;
928
196
    nlohmann::json jsonMPD;
929
196
    nlohmann::json json_iDomLOCK;
930
196
    nlohmann::json json433Mhz;
931
196
    //////////////////// iDom
932
196
    json_iDomLOCK["iDomLock"] = stateToString(my_data->idom_all_state.houseState);
933
196
    //////////////////// alarm
934
196
    jsonAlarm["alarm"] = my_data->main_iDomStatus->getObjectStateString("alarm");
935
196
    jsonAlarm["time"]  = my_data->alarmTime.time.getString();
936
196
    jsonAlarm["fromVolume"] = my_data->alarmTime.fromVolume;
937
196
    jsonAlarm["toVolume"] = my_data->alarmTime.toVolume;
938
196
    jsonAlarm["radioID"] = my_data->alarmTime.radioID;
939
196
    //////////////////// mpd
940
196
    jsonMPD["music"] = my_data->main_iDomStatus->getObjectStateString("music");
941
196
    jsonMPD["speakers"] = my_data->main_iDomStatus->getObjectStateString("speakers");
942
196
    ////////////////// 433Mhz
943
196
    auto switch433vector = my_data->main_REC->getSwitchPointerVector();
944
196
    for (auto v : switch433vector)
945
980
    {
946
980
        v->getName();
947
980
        json433Mhz[v->getName()] = stateToString(v->getState());
948
980
    }
949
196
    ///
950
196
    nlohmann::json json;
951
196
    json["iDom"] = json_iDomLOCK;
952
196
    json["ALARM"] = jsonAlarm;
953
196
    json["MPD"] = jsonMPD;
954
196
    json["433Mhz"] = json433Mhz;
955
196
956
196
    info.write(json);
957
196
#ifdef BT_TEST
958
196
    std::cout << json <<std::endl;
959
196
    std::cout << " saved to " << my_data->server_settings->saveFilePath <<std::endl;
960
196
#endif
961
196
}
962
963
void iDomTOOLS::readState_iDom()
964
8
{
965
8
    try
966
8
    {
967
8
        iDom_SAVE_STATE info(my_data->server_settings->saveFilePath);
968
8
        nlohmann::json jj = info.read();
969
8
#ifdef BT_TEST
970
8
        std::cout << "JSON: " << jj.dump(4) << std::endl;
971
8
#endif
972
8
        nlohmann::json json433MHz = jj.at("433Mhz");
973
8
974
28
        for (nlohmann::json::iterator it = json433MHz.begin(); it != json433MHz.end(); ++it)
975
20
        {
976
20
            if( it.value() == "ON"){
977
0
                my_data->main_iDomTools->turnOn433MHzSwitch(it.key());
978
0
            }
979
20
            else if ( it.value() == "OFF"){
980
0
                my_data->main_iDomTools->turnOff433MHzSwitch(it.key());
981
0
            }
982
20
        }
983
8
        auto iDomLock = jj.at("iDom").at("iDomLock").get<std::string>();
984
8
985
8
        if(iDomLock == "UNLOCK")
986
0
            unlockHome();
987
8
        else if (iDomLock == "LOCK")
988
4
            lockHome();
989
8
990
8
        auto mpdMusic = jj.at("MPD").at("music").get<std::string>();
991
8
        auto mpdSpeakers = jj.at("MPD").at("speakers").get<std::string>();
992
8
993
8
        if(mpdMusic == "PLAY")
994
4
            MPD_play(my_data);
995
4
        else if(mpdMusic == "STOP")
996
0
            MPD_stop();
997
8
        if(mpdSpeakers == "ON")
998
4
            turnOnSpeakers();
999
4
        else if(mpdSpeakers == "OFF")
1000
0
            turnOffSpeakers();
1001
8
1002
8
        auto alarmState = jj.at("ALARM").at("alarm").get<std::string>();
1003
8
        auto alarmTime  = jj.at("ALARM").at("time").get<std::string>();
1004
8
        my_data->alarmTime.fromVolume = jj.at("ALARM").at("fromVolume").get<int>();
1005
8
        my_data->alarmTime.toVolume = jj.at("ALARM").at("toVolume").get<int>();
1006
8
        my_data->alarmTime.radioID = jj.at("ALARM").at("radioID").get<int>();
1007
8
        my_data->alarmTime.time = Clock(alarmTime);
1008
8
1009
8
        if (alarmState == "ACTIVE"){
1010
4
            my_data->alarmTime.state = STATE::ACTIVE;
1011
4
            my_data->main_iDomStatus->setObjectState("alarm", my_data->alarmTime.state);
1012
4
            saveState_iDom();
1013
4
        }
1014
8
    }
1015
8
    catch(...)
1016
8
    {
1017
4
        log_file_mutex.mutex_lock();
1018
4
        log_file_cout << ERROR << "nie ma pliku json z stanem iDom"<< std::endl;
1019
4
        log_file_mutex.mutex_unlock();
1020
4
#ifdef BT_TEST
1021
4
        std::cout << "nie ma pliku json z stanem iDom" << std::endl;
1022
4
#endif
1023
4
    }
1024
8
}
1025
1026
std::string iDomTOOLS::startKodi_Thread()
1027
16
{
1028
16
    STATE kodiState = my_data->main_iDomStatus->getObjectState("KODI");
1029
16
    if (kodiState == STATE::ACTIVE)
1030
4
        return "kodi already run";
1031
12
1032
12
    return iDOM_THREAD::start_thread("kodi smartTV",useful_F::kodi,my_data);
1033
12
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/iDomTools/idomtools_mpd.cpp
Line
Count
Source
1
#include "idomtools.h"
2
#include "../blockQueue/blockqueue.h"
3
#include "../functions/functions.h"
4
5
void iDomTOOLS::MPD_play(thread_data* my_data)
6
44
{
7
44
    if(my_data->idom_all_state.houseState == STATE::UNLOCK)
8
24
    {
9
24
        blockQueue _q;
10
24
        _q._add(MPD_COMMAND::PLAY);
11
24
    }
12
20
    else
13
20
    {
14
20
        my_data->myEventHandler.run("MPD")->addEvent("MPD can not start due to home state: "+
15
20
                                                     stateToString(my_data->idom_all_state.houseState));
16
20
    }
17
44
}
18
19
void iDomTOOLS::MPD_stop()
20
52
{
21
52
    blockQueue _q;
22
52
    _q._add(MPD_COMMAND::STOP);
23
52
}
24
25
void iDomTOOLS::MPD_next()
26
8
{
27
8
    blockQueue _q;
28
8
    _q._add(MPD_COMMAND::NEXT);
29
8
}
30
31
void iDomTOOLS::MPD_prev()
32
8
{
33
8
    blockQueue _q;
34
8
    _q._add(MPD_COMMAND::PREV);
35
8
}
36
37
void iDomTOOLS::MPD_pause()
38
20
{
39
20
    blockQueue _q;
40
20
    _q._add(MPD_COMMAND::PAUSE);
41
20
}
42
43
void iDomTOOLS::MPD_volumeUp()
44
8
{
45
8
    blockQueue _q;
46
8
    _q._add(MPD_COMMAND::VOLUP);
47
8
}
48
49
void iDomTOOLS::MPD_volumeDown()
50
8
{
51
8
    blockQueue _q;
52
8
    _q._add(MPD_COMMAND::VOLDOWN);
53
8
}
54
55
void iDomTOOLS::MPD_volumeSet(thread_data *my_data, int vol)
56
48
{
57
48
    my_data->ptr_MPD_info->volume = vol;
58
48
    blockQueue _q;
59
48
    _q._add(MPD_COMMAND::VOLSET);
60
48
}
61
62
void iDomTOOLS::MPD_play(thread_data *my_data, int id)
63
16
{
64
16
    if(my_data->idom_all_state.houseState == STATE::UNLOCK)
65
8
    {
66
8
        my_data->ptr_MPD_info->currentSongID = id;
67
8
        blockQueue _q;
68
8
        _q._add(MPD_COMMAND::PLAY_ID);
69
8
    }
70
8
    else
71
8
    {
72
8
        my_data->myEventHandler.run("MPD")->addEvent("MPD can not start due to home state: "+
73
8
                                                     stateToString(my_data->idom_all_state.houseState));
74
8
    }
75
16
}
76
77
int iDomTOOLS::MPD_getVolume(thread_data *my_data)
78
44
{
79
44
    return my_data->ptr_MPD_info->volume;
80
44
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/iDomTools/idomtools_system.cpp
Line
Count
Source
1
#include "idomtools.h"
2
#include <sys/sysinfo.h>
3
#include <sys/utsname.h>
4
#include <sys/resource.h>
5
#include <sys/time.h>
6
#include <unistd.h>
7
8
std::string iDomTOOLS::getSystemInfo()
9
8
{
10
8
    double load[3];
11
8
    if (getloadavg(load, 3) != -1)
12
8
    {
13
8
#ifdef BT_TEST
14
8
        printf("load average : %f , %f , %f\n", load[0],load[1],load[2]);
15
8
#endif
16
8
    }
17
8
    const double megabyte = 1024 * 1024;
18
8
    struct sysinfo info;
19
8
    sysinfo(&info);
20
8
21
8
    long input_seconds = info.uptime;
22
8
    auto days = input_seconds / 60 / 60 / 24;
23
8
    auto hours = (input_seconds / 60 / 60) % 24;
24
8
    auto minutes = (input_seconds / 60) % 60;
25
8
    auto seconds = input_seconds % 60;
26
8
27
8
    std::stringstream ret;
28
8
    ret << "System uptime: " << days <<" day " << hours
29
8
        << " hours " << minutes << " minutes "
30
8
        << seconds << " seconds " << std::endl << "Load: "
31
8
        << (info.loads[0]/65536) << "% - 1 min, " <<(info.loads[1]/65536)
32
8
        << "% - 5 min, "<<(info.loads[2]/65536) << "% - 15 min." << std::endl
33
8
        << "process count : " << info.procs << std::endl
34
8
        << "total RAM   : "<< (info.totalram / megabyte)<< "MB" << std::endl
35
8
        << "free RAM   : " << (info.freeram / megabyte) << "MB" << std::endl;
36
8
37
8
    return ret.str();
38
8
}
39
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/iDomTools/lightning.cpp
Line
Count
Source
1
#include "lightning.h"
2
3
LIGHTNING::LIGHTNING()
4
1.60k
{
5
1.60k
    puts("LIGHTNING::LIGHTNING()");
6
1.60k
}
7
8
LIGHTNING::~LIGHTNING()
9
1.60k
{
10
1.60k
    puts("LIGHTNING::~LIGHTNING()");
11
1.60k
}
12
13
CARDINAL_DIRECTIONS::ALARM_INFO LIGHTNING::lightningAlert(nlohmann::json jj)
14
52
{
15
52
    CARDINAL_DIRECTIONS::ALARM_INFO data;
16
52
    nlohmann::json i;
17
52
18
52
#ifdef BT_TEST
19
52
    std::cout <<"\n\n data all " << i.dump(4) <<" size:"<< i.size() <<std::endl;
20
52
#endif
21
52
    if (jj.find("response") != jj.end())
22
48
    {
23
48
        i = jj.at("response").get<nlohmann::json>();
24
48
    }
25
4
    else
26
4
    {
27
4
        std::cout << " zly JSON " <<std::endl;
28
4
        return data;
29
4
    }
30
48
31
48
    auto _size = i.size();
32
48
    if (_size == 0)
33
16
    {
34
16
        data.riseAlarm = false;
35
16
        return data;
36
16
    }
37
32
    STATISTIC<int> ageAver(_size);
38
32
    STATISTIC<double> distanceKmAver(_size);
39
32
    STATISTIC<int> bearingAver(_size);
40
584
    for (auto j : i){
41
584
#ifdef BT_TEST
42
584
   //     std::cout <<"\n distance " << j.at("relativeTo").at("bearingENG").get<std::string>() << std::endl;
43
584
   //     std::cout <<"distance " << j.at("relativeTo").at("distanceKM").get<double>() << std::endl;
44
584
   //     std::cout <<"timestamp " << j.at("age").get<int>() << std::endl;
45
584
#endif
46
584
        ageAver.push_back(j.at("age").get<int>());
47
584
        distanceKmAver.push_back(j.at("relativeTo").at("distanceKM").get<double>());
48
584
        bearingAver.push_back(static_cast<int>(CARDINAL_DIRECTIONS::stringToCardinalDirectionsEnum(
49
584
                                                   j.at("relativeTo").at("bearingENG").get<std::string>()))
50
584
                              );
51
584
    }
52
32
    data.bearingENG = static_cast<CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM>(bearingAver.mode());
53
32
    data.distance = distanceKmAver.average();
54
32
    data.timestamp = ageAver.median();
55
32
56
32
    data.data.str(std::string());
57
32
    data.data << "ilość uderzeń: "<< _size << "\\n";
58
32
    data.data << "średni czas upłynięty od ostatniego uderzenia pioruna: "<< data.timestamp << " sek \\n";
59
32
    data.data << "średnia odległość ostatniego uderzenia pieruna: "<< data.distance <<" km \\n ";
60
32
    data.data << "kierunek uderzeń piorunów: " << CARDINAL_DIRECTIONS::cardinalDirectionsEnumToHuman(data.bearingENG);
61
32
62
32
    if(i.size() > 0){
63
32
        // std::cout << "jest size: " << i.size()<<std::endl;
64
32
        data.riseAlarm = true;
65
32
    }
66
32
67
32
    return data;
68
32
}
69
70
bool LIGHTNING::checkLightningAlert(CARDINAL_DIRECTIONS::ALARM_INFO *info)
71
60
{
72
60
#ifdef BT_TEST
73
60
    std::cout << "LIGHTNING::checkLightningAlert() bool "<< info->riseAlarm <<" local " << alarmState << std::endl
74
60
              << " distance " << info->distance << std::endl;
75
60
#endif
76
60
    if(info->riseAlarm == false && alarmState == false){
77
16
#ifdef BT_TEST
78
16
        std::cout << "(info->riseAlarm == false || alarmState == false)"<<std::endl;
79
16
#endif
80
16
        return false;
81
16
    }
82
44
    if(info->riseAlarm == false && alarmState == true){
83
8
#ifdef BT_TEST
84
8
        std::cout << "(info->riseAlarm == false || alarmState == true)"<<std::endl;
85
8
#endif
86
8
        alarmState = false;
87
8
        return false;
88
8
    }
89
36
    if(info->riseAlarm == true && alarmState == false){
90
20
91
20
#ifdef BT_TEST
92
20
        std::cout << "(info->riseAlarm == true || alarmState == false)"<<std::endl;
93
20
#endif
94
20
        alarmState = true;
95
20
        lightningTime = Clock::getTime();
96
20
        oldDistance = info->distance;
97
20
        std::cout << " w true oldDistance: "<< oldDistance <<std::endl;
98
20
        return true;
99
20
    }
100
16
101
16
#ifdef BT_TEST
102
16
    std::cout << "checkLightningAlert() - dystans"<<std::endl;
103
16
    std::cout << "Dystans: " <<info->distance << " oldDistance: "<< oldDistance <<std::endl;
104
16
#endif
105
16
    if(oldDistance > info->distance)
106
4
    {
107
4
108
4
        oldDistance = info->distance;
109
4
        return true;
110
4
    }
111
12
    else
112
12
    {
113
12
        oldDistance = info->distance;
114
12
    }
115
16
    ////////////////clear
116
16
    //oldDistance = 0.0;
117
16
    return false;
118
16
}
119
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/iDomTools/lightning.h
Line
Count
Source (jump to first uncovered line)
1
#ifndef LIGHTNING_H
2
#define LIGHTNING_H
3
#include <iostream>
4
5
#include "../../libs/Statistic/statistic.h"
6
#include "../../libs/useful/useful.h"
7
8
#include "idomtools_useful.h"
9
#include "json.hpp"
10
11
class CARDINAL_DIRECTIONS{
12
public:
13
    enum class CARDINAL_DIRECTIONS_ENUM{
14
        /*
15
           N
16
        NNW NNE
17
      NW       NE
18
   WNW         ENE
19
 W            E
20
   WSW       ESE
21
      SW     SE
22
        SSW  SSE
23
           S
24
    */
25
26
        N = 1,NNE,NE,ENE,E,ESE,SE,SSE,S,SSW,SW,WSW,W,WNW,NW,NNW,ERROR
27
    };
28
592
    static CARDINAL_DIRECTIONS_ENUM stringToCardinalDirectionsEnum(std::string s){
29
592
        if (s == "N")      return CARDINAL_DIRECTIONS_ENUM::N;
30
588
        else if (s == "NNE")    return CARDINAL_DIRECTIONS_ENUM::NNE;
31
540
        else if (s == "NE")     return CARDINAL_DIRECTIONS_ENUM::NE;
32
516
        else if (s == "ENE")    return CARDINAL_DIRECTIONS_ENUM::ENE;
33
204
        else if (s == "E")      return CARDINAL_DIRECTIONS_ENUM::E;
34
12
        else if (s == "ESE")    return CARDINAL_DIRECTIONS_ENUM::ESE;
35
12
        else if (s == "SE")     return CARDINAL_DIRECTIONS_ENUM::SE;
36
12
        else if (s == "SSE")    return CARDINAL_DIRECTIONS_ENUM::SSE;
37
12
        else if (s == "S")      return CARDINAL_DIRECTIONS_ENUM::S;
38
12
        else if (s == "SSW")    return CARDINAL_DIRECTIONS_ENUM::SSW;
39
12
        else if (s == "SW")     return CARDINAL_DIRECTIONS_ENUM::SW;
40
12
        else if (s == "WSW")    return CARDINAL_DIRECTIONS_ENUM::WSW;
41
4
        else if (s == "W")      return CARDINAL_DIRECTIONS_ENUM::W;
42
4
        else if (s == "WNW")    return CARDINAL_DIRECTIONS_ENUM::WNW;
43
4
        else if (s == "NW")     return CARDINAL_DIRECTIONS_ENUM::NW;
44
4
        else if (s == "NNW")    return CARDINAL_DIRECTIONS_ENUM::NNW;
45
4
        else                    return CARDINAL_DIRECTIONS_ENUM::ERROR;
46
0
    }
47
48
8
    static std::string cardinalDirectionsEnumToString(CARDINAL_DIRECTIONS_ENUM e){
49
8
        switch (e){
50
8
        case CARDINAL_DIRECTIONS_ENUM::N:
51
0
            return "N";
52
8
        case CARDINAL_DIRECTIONS_ENUM::NNE:
53
0
            return "NNE";
54
8
        case CARDINAL_DIRECTIONS_ENUM:: NE:
55
0
            return "NE";
56
8
        case CARDINAL_DIRECTIONS_ENUM::ENE:
57
0
            return "ENE";
58
8
        case CARDINAL_DIRECTIONS_ENUM::E:
59
0
            return "E";
60
8
        case CARDINAL_DIRECTIONS_ENUM::ESE:
61
4
            return "ESE";
62
8
        case CARDINAL_DIRECTIONS_ENUM::SE:
63
0
            return "SE";
64
8
        case CARDINAL_DIRECTIONS_ENUM::SSE:
65
0
            return "SSE";
66
8
        case CARDINAL_DIRECTIONS_ENUM::S:
67
0
            return "S";
68
8
        case CARDINAL_DIRECTIONS_ENUM::SSW:
69
0
            return "SSW";
70
8
        case CARDINAL_DIRECTIONS_ENUM::SW:
71
0
            return "SW";
72
8
        case CARDINAL_DIRECTIONS_ENUM::WSW:
73
0
            return "WSW";
74
8
        case CARDINAL_DIRECTIONS_ENUM::W:
75
0
            return "W";
76
8
        case CARDINAL_DIRECTIONS_ENUM::WNW:
77
0
            return "WNW";
78
8
        case CARDINAL_DIRECTIONS_ENUM::NW:
79
0
            return "NW";
80
8
        case CARDINAL_DIRECTIONS_ENUM::NNW:
81
0
            return "NNW";
82
8
        default:
83
4
            return "UNKNOWN DIRECTION";
84
0
        }
85
0
    }
86
32
    static std::string cardinalDirectionsEnumToHuman(CARDINAL_DIRECTIONS_ENUM e){
87
32
        switch (e){
88
32
        case CARDINAL_DIRECTIONS_ENUM::N:
89
0
            return "północ";
90
32
        case CARDINAL_DIRECTIONS_ENUM::NNE:
91
0
            return "północ - północny wschód";
92
32
        case CARDINAL_DIRECTIONS_ENUM:: NE:
93
0
            return "północny wschód";
94
32
        case CARDINAL_DIRECTIONS_ENUM::ENE:
95
24
            return "wschód - północny wschód";
96
32
        case CARDINAL_DIRECTIONS_ENUM::E:
97
0
            return "wschód";
98
32
        case CARDINAL_DIRECTIONS_ENUM::ESE:
99
0
            return "wschód - południowy wschód";
100
32
        case CARDINAL_DIRECTIONS_ENUM::SE:
101
0
            return "południowy wschód";
102
32
        case CARDINAL_DIRECTIONS_ENUM::SSE:
103
0
            return "południe - południowy wschód";
104
32
        case CARDINAL_DIRECTIONS_ENUM::S:
105
0
            return "południe";
106
32
        case CARDINAL_DIRECTIONS_ENUM::SSW:
107
0
            return "południe - południowy zachów";
108
32
        case CARDINAL_DIRECTIONS_ENUM::SW:
109
0
            return "południowy zachów";
110
32
        case CARDINAL_DIRECTIONS_ENUM::WSW:
111
8
            return "zachód - południowy zachów";
112
32
        case CARDINAL_DIRECTIONS_ENUM::W:
113
0
            return "zachód";
114
32
        case CARDINAL_DIRECTIONS_ENUM::WNW:
115
0
            return "zachód - północny zachód";
116
32
        case CARDINAL_DIRECTIONS_ENUM::NW:
117
0
            return "północny zachód";
118
32
        case CARDINAL_DIRECTIONS_ENUM::NNW:
119
0
            return "północ - północny zachód";
120
32
        default:
121
0
            return "UNKNOWN DIRECTION";
122
0
        }
123
0
    }
124
    struct ALARM_INFO{
125
        ALARM_INFO():
126
            riseAlarm(false),
127
            timestamp(0),
128
            distance(0.0),
129
            bearingENG(CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM::ERROR)
130
1.64k
        {
131
1.64k
            data << "NULL";
132
1.64k
        }
133
        ALARM_INFO(const ALARM_INFO &s):
134
            riseAlarm(s.riseAlarm),
135
            data(s.data.str()),
136
            timestamp(s.timestamp),
137
            distance(s.distance),
138
            bearingENG(s.bearingENG)
139
16
        {
140
16
        }
141
        ALARM_INFO& operator = (const ALARM_INFO& s)
142
56
        {
143
56
            this->data.str(std::string());
144
56
            this->riseAlarm = s.riseAlarm;
145
56
            this->data << s.data.str();
146
56
            this->timestamp = s.timestamp;
147
56
            this->distance = s.distance;
148
56
            this->bearingENG = s.bearingENG;
149
56
            return *this;
150
56
        }
151
152
        bool riseAlarm;
153
        std::stringstream data;
154
        unsigned int timestamp; //second
155
        double distance; //km
156
        CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM bearingENG;
157
    };
158
};
159
160
class LIGHTNING
161
{
162
public:
163
    LIGHTNING();
164
    ~LIGHTNING();
165
    CARDINAL_DIRECTIONS::ALARM_INFO lightningAlert(nlohmann::json jj);
166
    bool checkLightningAlert(CARDINAL_DIRECTIONS::ALARM_INFO* info);
167
private:
168
    bool alarmState = false;
169
    Clock lightningTime;
170
    double oldDistance = 0.0;
171
};
172
173
#endif // LIGHTNING_H
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/iDomTools/test/iDomTools_fixture.h
Line
Count
Source
1
#include <gtest/gtest.h>
2
#include "test_data.h"
3
#include "../idomtools.h"
4
#include "../../src/functions/functions.h"
5
#include "../../RADIO_433_eq/radio_433_eq.h"
6
#include "testJSON.h"
7
8
class iDomTOOLS_ClassTest : public testing::Test
9
{
10
public:
11
    TEST_JSON test_Json;
12
    LIGHTNING test_lightning;
13
    CARDINAL_DIRECTIONS::ALARM_INFO test_struct;
14
    thread_data test_my_data;
15
    iDomSTATUS test_status;
16
    config test_server_set;
17
    std::shared_ptr<RADIO_EQ_CONTAINER> test_rec;
18
    iDOM_STATE main_iDomStatus;
19
    ALERT test_alarmTime;
20
    pilot_led test_pilot_led;
21
    MPD_info test_ptr_MPD;
22
23
    /// pointer
24
    iDomTOOLS* test_idomTOOLS;
25
    /////// method
26
    iDomTOOLS_ClassTest()//:test_rec(&test_my_data)
27
788
    {
28
788
        std::cout << "konstruktor testu " <<std::endl;
29
788
    }
30
    void SetUp()
31
784
    {
32
784
        std::cout << "SetUP testu iDomTOOLS_ClassTest" <<std::endl;
33
784
        test_rec = std::make_shared<RADIO_EQ_CONTAINER>(&test_my_data);
34
784
        test_server_set.TS_KEY = "key test";
35
784
        test_server_set.viberSender = "test sender";
36
784
        test_server_set.viberReceiver = {"R1","R2"};
37
784
        test_server_set.saveFilePath = "/mnt/ramdisk/iDomStateTest2.save";
38
784
        test_server_set.radio433MHzConfigFile = "/mnt/ramdisk/433_eq_conf.json";
39
784
        test_rec->loadConfig(test_server_set.radio433MHzConfigFile);
40
784
41
784
        test_my_data.main_REC = test_rec;
42
784
        test_my_data.server_settings = &test_server_set;
43
784
        test_my_data.main_iDomStatus = &test_status;
44
784
        test_my_data.alarmTime = test_alarmTime;
45
784
        test_my_data.idom_all_state = main_iDomStatus;
46
784
        test_my_data.ptr_pilot_led = &test_pilot_led;
47
784
48
784
        test_status.addObject("house");
49
784
50
784
        /////////// create
51
784
        test_idomTOOLS = new iDomTOOLS(&test_my_data);
52
784
53
784
        test_my_data.main_iDomTools = test_idomTOOLS;
54
784
        test_ptr_MPD.volume = 3;
55
784
        test_my_data.ptr_MPD_info = &test_ptr_MPD;
56
784
57
784
        useful_F::myStaticData = &test_my_data;
58
784
    }
59
60
    void TearDown()
61
784
    {
62
784
        delete test_idomTOOLS;
63
784
    }
64
};
65
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/iDomTools/test/iDom_server_BT.cpp
Line
Count
Source
1
#include <gtest/gtest.h>
2
#include <curl/curl.h>
3
#include "iDomTools_fixture.h"
4
5
class iDom_server_Class : public iDomTOOLS_ClassTest
6
{
7
protected:
8
    TEST_JSON test_Json;
9
    LIGHTNING test_lightning;
10
    CARDINAL_DIRECTIONS::ALARM_INFO test_struct;
11
    virtual void SetUp() final
12
4
    {
13
4
        std::cout << "konfiguracja przed testem iDom_server_Class " <<std::endl;
14
4
    }
15
16
    virtual void TearDown() final
17
4
    {
18
4
        std::cout << "czyszczenie po tescie iDom_server_Class " <<std::endl;
19
4
    }
20
};
21
22
TEST_F(iDom_server_Class, LED_Strip )
23
4
{
24
4
    LED_Strip test_LED("1","60","255","255","255", "WHITE");
25
4
    EXPECT_STREQ(test_LED.getColorName().c_str(), "WHITE");
26
4
    EXPECT_STREQ(test_LED.get(0,60).c_str(),"LED:[1-60-255-255-255];");
27
4
    EXPECT_STREQ(test_LED.makeCommand("1","60","128","128","128").c_str(),"LED:[1-60-128-128-128];");
28
4
29
4
    test_LED.set("1","60","0","255","0","UNKNOWN");
30
4
31
4
    EXPECT_STREQ(test_LED.getColorName().c_str(), "UNKNOWN");
32
4
    EXPECT_STREQ(test_LED.get(0,60).c_str(),"LED:[1-60-0-255-0];");
33
4
34
4
    test_LED.set(50,51,1,2,3,"BLACK");
35
4
36
4
    EXPECT_STREQ(test_LED.getColorName().c_str(), "BLACK");
37
4
    EXPECT_STREQ(test_LED.get(0,60).c_str(),"LED:[50-51-1-2-3];");
38
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/iDomTools/test/idomTools_BT.cpp
Line
Count
Source
1
#include <gtest/gtest.h>
2
#include <curl/curl.h>
3
4
#include "iDomTools_fixture.h"
5
6
TEST_F(iDomTOOLS_ClassTest, smog)
7
4
{
8
4
    std::string smog = test_idomTOOLS->getSmog();
9
4
    puts(smog.c_str());
10
4
    puts(" smog");
11
4
    ASSERT_GE(smog.size(),1);
12
4
13
4
    unsigned int smog_int = std::stoi(smog);
14
4
    ASSERT_GT(smog_int,1);
15
4
    ASSERT_LT(smog_int,1000);
16
4
}
17
18
TEST_F(iDomTOOLS_ClassTest, hasTemperatureChange)
19
4
{
20
4
    std::cout << "##################################### 0" <<std::endl;
21
4
22
4
    TEST_DATA::return_send_to_arduino = "20.0:-1.0;";
23
4
    test_idomTOOLS->send_temperature_thingSpeak();
24
4
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("outside"),TEMPERATURE_STATE::Under);
25
4
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("inside"),TEMPERATURE_STATE::NoChanges);
26
4
    std::cout << "##################################### 1" <<std::endl;
27
4
28
4
    TEST_DATA::return_send_to_arduino = "25.4:0.0;";
29
4
    test_idomTOOLS->send_temperature_thingSpeak();
30
4
31
4
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("outside"),TEMPERATURE_STATE::NoChanges);
32
4
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("inside"),TEMPERATURE_STATE::Over);
33
4
34
4
    std::cout << "##################################### 2" <<std::endl;
35
4
36
4
    TEST_DATA::return_send_to_arduino = "21.0:1.0;";
37
4
    test_idomTOOLS->send_temperature_thingSpeak();
38
4
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("outside"),TEMPERATURE_STATE::Over);
39
4
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("inside"),TEMPERATURE_STATE::Under);
40
4
41
4
    std::cout << "##################################### 3" <<std::endl;
42
4
    TEST_DATA::return_send_to_arduino = "21.0:5.0;";
43
4
    test_idomTOOLS->send_temperature_thingSpeak();
44
4
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("outside"),TEMPERATURE_STATE::NoChanges);
45
4
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("inside"),TEMPERATURE_STATE::NoChanges);
46
4
47
4
    std::cout << "##################################### 4" <<std::endl;
48
4
    TEST_DATA::return_send_to_arduino = "21.0:4.0;";
49
4
    test_idomTOOLS->send_temperature_thingSpeak();
50
4
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("outside"),TEMPERATURE_STATE::NoChanges);
51
4
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("inside"),TEMPERATURE_STATE::NoChanges);
52
4
    std::cout << "##################################### 5" <<std::endl;
53
4
54
4
    TEST_DATA::return_send_to_arduino = "31.9:11.11;";
55
4
    test_idomTOOLS->send_temperature_thingSpeak();
56
4
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("outside"),TEMPERATURE_STATE::NoChanges);
57
4
    EXPECT_EQ(test_idomTOOLS->allThermometer.getLastState("inside"),TEMPERATURE_STATE::Over);
58
4
    std::cout << "##################################### 6" <<std::endl;
59
4
60
4
    ////// getThermoStats
61
4
62
4
    std::cout << "WYNIK: " << test_idomTOOLS->getThermoStats("inside") <<std::endl;
63
4
}
64
65
TEST_F(iDomTOOLS_ClassTest, weatherAlert)
66
4
{
67
4
    std::string test_data_from_www = " <div style=\"margin:0;padding:0;width:350px;font:0.8em Lucida,Arial,sans-seri f;background:#FFC\">"
68
4
                                     "<p style=\"margin:1px;padding:1px;text-align:center;background:#FF9;borde \\ r:1px dotted\"><b><a href=\"http://burze.dzis.net?page=wyszukiwarka&amp;miejscowos\\ c=krakow\" target=\"_blank\" style=\"color:#00E\">krakow</a></b>"
69
4
                                     "<i>(50°03'N 19°57'E)</i> </p>"
70
4
                                     "<dl style=\"margin:1px 1px 0 1px;padding:0;cl ear:both;background:#FFD;border:1px dotted;overflow:auto;color:green;text-align:\\ center\">Zarejestrowano 54 wyładowania atmosferyczne w promieniu 300km . Najbliższe 79.76km na zachód."
71
4
                                     "</dl> <dl style=\"margin:1px 1px 0 1px;padding:0;cl ear:both;background:#FFD;border:1px dotted;overflow:auto;color:green;text-align: \\ center\">Mróz, brak ostrzeżeń</dl>"
72
4
                                     "<dl style=\"margin:1px 1px 0 1px;padding:0;clear:both ;background:#FFD;border:1px dotted;overflow:auto;color:green;text-align:center\">  Upał, brak ostrzeżeń</dl>"
73
4
                                     "<dl style=\"margin:1px 1px 0 1px;padding:0;clear:both ;background:#FFD;border:1px dotted;overflow:auto;color:green;text-align:center\">  Wiatr, brak ostrzeżeń</dl>"
74
4
                                     "<dl style=\"margin:1px 1px 0 1px;padding:0;clear:both ;background:#FFD;border:1px dotted;overflow:auto;color:green;text-align:center\">  Opady, brak ostrzeżeń</dl>"
75
4
                                     "<dl style=\"margin:1px 1px 0 1px;padding:0;clear:both ;background:#FFD;border:1px dotted;overflow:auto;color:green;text-align:center\">  Burze, brak ostrzeżeń</dl>"
76
4
                                     "<dl style=\"margin:1px 1px 0 1px;padding:0;clear:both ;background:#FFD;border:1px dotted;overflow:auto;color:green;text-align:center\">  Trąby powietrzne, brak ostrzeżeń</dl></div>";
77
4
78
4
    std::vector<WEATHER_ALER> test_WA;
79
4
    test_WA =  test_idomTOOLS->getAlert(test_data_from_www);
80
8
    EXPECT_EQ(1,test_WA.size()) << "ZŁY ROZMIAR VEKTORA WA";
81
4
}
82
83
4
TEST_F(iDomTOOLS_ClassTest, send_temperature_thingSpeak){
84
4
85
4
    TEST_DATA::return_send_to_arduino = "-2.3:-2";
86
4
    TEST_DATA::return_httpPost_expect = "NULL";
87
4
    EXPECT_STREQ(TEST_DATA::return_httpPost_expect.c_str(),"NULL");
88
4
    test_idomTOOLS->send_temperature_thingSpeak();
89
4
    std::cout << "DATA: "<< TEST_DATA::return_httpPost_expect <<std::endl;
90
4
    EXPECT_STREQ(TEST_DATA::return_httpPost_expect.c_str(),"httpPost");
91
4
}
92
93
TEST_F(iDomTOOLS_ClassTest, checkAlarm)
94
4
{
95
4
    blockQueue test_q;
96
4
    unsigned int fromVol = 48;
97
4
    unsigned int  toVol = 57;
98
4
99
4
    ///////////////////////////////////// to save
100
4
    test_status.setObjectState("house",STATE::UNLOCK);
101
4
    test_status.setObjectState("music", STATE::PLAY);
102
4
    test_status.setObjectState("speakers", STATE::ON);
103
4
    test_my_data.idom_all_state.houseState = STATE::LOCK;
104
4
105
4
    test_status.setObjectState("listwa",STATE::ON);
106
4
107
4
    test_alarmTime.time = Clock::getTime();
108
4
    test_alarmTime.state = STATE::ACTIVE;
109
4
    test_alarmTime.toVolume = 58;
110
4
    test_alarmTime.fromVolume = 48;
111
4
    test_status.setObjectState("alarm", test_alarmTime.state);
112
4
    test_my_data.alarmTime = test_alarmTime;
113
4
    useful_F::myStaticData = &test_my_data;
114
4
115
4
    //////////////////////////////////////////////////////////////
116
4
117
4
    test_my_data.alarmTime.time = Clock::getTime();
118
4
    test_my_data.alarmTime.state = STATE::ACTIVE;
119
4
120
4
    EXPECT_EQ(test_my_data.alarmTime.state, STATE::ACTIVE);
121
4
122
40
    for(unsigned int i = fromVol; i<toVol; ++i)
123
36
    {
124
36
        test_idomTOOLS->checkAlarm();
125
36
        test_q._get();
126
72
        EXPECT_EQ(test_my_data.alarmTime.state, STATE::WORKING)<< "zły stan w for " << i<< " "<< toVol;
127
72
        EXPECT_EQ(test_my_data.ptr_MPD_info->volume, i+1) << "zły poziom glosnosci w for";
128
36
    }
129
4
130
4
    test_idomTOOLS->checkAlarm();
131
4
132
8
    EXPECT_EQ(test_my_data.alarmTime.state, STATE::DEACTIVE) << "nie jest STATE::DEACTIVE";
133
8
    EXPECT_EQ(test_my_data.ptr_MPD_info->volume, toVol)<< "nie inkrementowane?";
134
4
135
4
}
136
137
TEST_F(iDomTOOLS_ClassTest, homeLockPlayStopMusic)
138
4
{
139
4
    ///////////////////////////////////// to save
140
4
    test_status.setObjectState("house",STATE::UNDEFINE);
141
4
    test_status.setObjectState("music", STATE::PLAY);
142
4
    test_status.setObjectState("speakers", STATE::ON);
143
4
    test_my_data.idom_all_state.houseState = STATE::LOCK;
144
4
145
4
    test_status.setObjectState("listwa",STATE::ON);
146
4
147
4
    test_alarmTime.time = Clock::getTime();
148
4
    test_alarmTime.state = STATE::ACTIVE;
149
4
    test_status.setObjectState("alarm", test_alarmTime.state);
150
4
151
4
    blockQueue test_q;
152
4
    test_q._clearAll();
153
4
    EXPECT_EQ(test_q._size(),0);
154
4
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNDEFINE);
155
4
    test_idomTOOLS->lockHome();
156
4
    EXPECT_EQ(test_status.getObjectState("house"),STATE::LOCK);
157
4
    test_idomTOOLS->MPD_play(&test_my_data);
158
4
    EXPECT_EQ(test_q._size(),0);
159
4
    test_idomTOOLS->unlockHome();
160
4
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNLOCK);
161
4
    test_idomTOOLS->MPD_play(&test_my_data);
162
4
    EXPECT_EQ(test_q._size(),1);
163
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PLAY);
164
4
    EXPECT_EQ(test_q._size(),0);
165
4
    test_idomTOOLS->lockHome();
166
4
    EXPECT_EQ(test_status.getObjectState("house"),STATE::LOCK);
167
4
    test_idomTOOLS->MPD_stop();
168
4
    EXPECT_EQ(test_q._size(),1);
169
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::STOP);
170
4
    EXPECT_EQ(test_q._size(),0);
171
4
    EXPECT_EQ(test_status.getObjectState("house"),STATE::LOCK);
172
4
    std::string returnedString = test_status.getAllObjectsStateString();
173
4
    EXPECT_THAT(returnedString, testing::HasSubstr("LOCK"));
174
4
}
175
176
TEST_F(iDomTOOLS_ClassTest, buttonPressed)
177
4
{
178
4
    std::string button433MHz_id = "01e7be";
179
4
    std::string pressedButtonName = test_idomTOOLS->buttonPressed(button433MHz_id);
180
4
    EXPECT_EQ(1, test_my_data.main_REC->getButtonPointerVector().size());
181
4
    EXPECT_STREQ(std::to_string(button433MHz_id).c_str(),
182
4
                 test_my_data.main_REC->getButtonPointerVector().at(0)->getID().c_str());
183
4
    EXPECT_STREQ(pressedButtonName.c_str(), "locker");
184
4
185
4
    EXPECT_THROW(test_idomTOOLS->buttonPressed(button433MHz_id+"a"),
186
4
                 std::string);
187
4
}
188
189
TEST_F(iDomTOOLS_ClassTest, button433MHzPressedAction_lockerUnlock)
190
4
{
191
4
    blockQueue test_q;
192
4
    test_q._clearAll();
193
4
194
4
    test_idomTOOLS->unlockHome();
195
4
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNLOCK);
196
4
197
16
    for(auto i =0 ; i < 3; ++i){
198
12
        test_idomTOOLS->button433MHzPressedAction("locker");
199
12
    }
200
4
    EXPECT_EQ(test_status.getObjectState("house"),STATE::LOCK);
201
4
202
4
    EXPECT_EQ(test_q._size(),1);
203
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::STOP);
204
4
205
4
}
206
207
TEST_F(iDomTOOLS_ClassTest, button433MHzPressedAction_lockerLock)
208
4
{
209
4
    blockQueue test_q;
210
4
    test_q._clearAll();
211
4
212
8
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNDEFINE) << "nie jest UNDEFINED";
213
4
214
4
    test_idomTOOLS->button433MHzPressedAction("locker");
215
8
    EXPECT_EQ(test_status.getObjectState("house"),STATE::UNLOCK)<< "nie jest UNLOCK";
216
4
217
4
    EXPECT_EQ(test_q._size(),1);
218
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PLAY);
219
4
    EXPECT_EQ(test_q._size(),0);
220
4
}
221
222
TEST_F(iDomTOOLS_ClassTest, testCPU_Load)
223
4
{
224
4
    std::cout <<"TEST LOAD" << std::endl;
225
4
    std::cout << test_idomTOOLS->getSystemInfo() << std::endl;
226
4
}
227
TEST_F(iDomTOOLS_ClassTest, stringToCardinalDirectionsEnum)
228
4
{
229
4
    EXPECT_EQ(CARDINAL_DIRECTIONS::stringToCardinalDirectionsEnum("NWWA"),
230
4
              CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM::ERROR);
231
4
    EXPECT_EQ(CARDINAL_DIRECTIONS::stringToCardinalDirectionsEnum("N"),
232
4
              CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM::N);
233
4
}
234
235
TEST_F(iDomTOOLS_ClassTest, cardinalDirectionsEnumToString)
236
4
{
237
4
    EXPECT_STREQ( CARDINAL_DIRECTIONS::cardinalDirectionsEnumToString(CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM::ERROR).c_str(),
238
4
                  "UNKNOWN DIRECTION");
239
4
    EXPECT_STREQ( CARDINAL_DIRECTIONS::cardinalDirectionsEnumToString(CARDINAL_DIRECTIONS::CARDINAL_DIRECTIONS_ENUM::ESE).c_str(),
240
4
                  "ESE");
241
4
}
242
243
TEST_F(iDomTOOLS_ClassTest, saveState_readState)
244
4
{
245
4
    test_status.setObjectState("house",STATE::UNLOCK);
246
4
    //////////////////// mpd
247
4
    test_status.setObjectState("music", STATE::PLAY);
248
4
    test_status.setObjectState("speakers", STATE::ON);
249
4
    test_my_data.idom_all_state.houseState = STATE::LOCK;
250
4
251
4
    test_status.setObjectState("listwa",STATE::ON);
252
4
    test_alarmTime.time = Clock::getTime();
253
4
    test_alarmTime.state = STATE::ACTIVE;
254
4
    test_alarmTime.fromVolume = 0;
255
4
    test_alarmTime.toVolume = 100;
256
4
    test_alarmTime.radioID = 44;
257
4
    test_my_data.alarmTime = test_alarmTime;
258
4
    test_status.setObjectState("alarm", test_alarmTime.state);
259
4
260
4
    test_idomTOOLS->saveState_iDom();
261
4
262
4
    nlohmann::json testJson;
263
4
    std::ifstream i(test_server_set.saveFilePath);
264
4
    i >> testJson;
265
4
    EXPECT_STREQ(test_status.getObjectStateString("music").c_str(),
266
4
                 testJson.at("MPD").at("music").get<std::string>().c_str() );
267
4
    EXPECT_STREQ((test_status.getObjectStateString("alarm")).c_str(),
268
4
                 testJson.at("ALARM").at("alarm").get<std::string>().c_str() );
269
4
    EXPECT_EQ(test_alarmTime.radioID,
270
4
              testJson.at("ALARM").at("radioID").get<int>() );
271
4
    EXPECT_EQ(test_alarmTime.fromVolume,
272
4
              testJson.at("ALARM").at("fromVolume").get<int>() );
273
4
    EXPECT_EQ(test_alarmTime.toVolume,
274
4
              testJson.at("ALARM").at("toVolume").get<int>() );
275
4
    ////////////////////////////////// read
276
4
    test_idomTOOLS->readState_iDom();
277
4
    EXPECT_EQ(test_my_data.alarmTime.state,STATE::ACTIVE);
278
4
279
4
    test_my_data.server_settings->saveFilePath = "null";
280
4
    EXPECT_NO_THROW(test_idomTOOLS->readState_iDom());
281
4
}
282
283
TEST_F(iDomTOOLS_ClassTest, getLightningStruct)
284
4
{
285
4
    LIGHTNING test_lightning;
286
4
    test_struct = test_lightning.lightningAlert(test_Json.jj_lightning);
287
4
288
4
    test_idomTOOLS->setLightningStruct(test_struct);
289
4
290
4
    bool test_result = test_lightning.checkLightningAlert(&test_struct);
291
4
    EXPECT_TRUE(test_result);
292
4
293
4
    auto test_alert_info = test_idomTOOLS->getLightningStruct();
294
4
    EXPECT_EQ(test_alert_info.timestamp,210);
295
4
}
296
TEST_F(iDomTOOLS_ClassTest, checkLightning)
297
4
{
298
4
    test_my_data.server_settings->lightningApiURL = "http://cyniu88.no-ip.pl/test/json/lightning.json";
299
4
    test_idomTOOLS->checkLightning();
300
4
    auto test_alert_info = test_idomTOOLS->getLightningStruct();
301
4
    EXPECT_EQ(test_alert_info.timestamp,210);
302
4
}
303
304
TEST_F(iDomTOOLS_ClassTest, updateTemperatureStats)
305
4
{
306
4
    TEST_DATA::return_send_to_arduino = "12:12";
307
4
    test_idomTOOLS->updateTemperatureStats();
308
4
    TEST_DATA::return_send_to_arduino = "16:16";
309
4
    test_idomTOOLS->updateTemperatureStats();
310
4
311
4
    ////////////// maleje na mieskzaniu
312
4
    TEST_DATA::return_send_to_arduino = "12:16";
313
4
    test_idomTOOLS->updateTemperatureStats();
314
4
    EXPECT_THAT(TEST_DATA::return_viber_msg,testing::HasSubstr("temperatura maleje"));
315
4
    EXPECT_THAT(TEST_DATA::return_viber_msg,testing::HasSubstr("mieszkaniu"));
316
4
317
4
    ////////////// maleje na polu
318
4
    TEST_DATA::return_send_to_arduino = "12:12";
319
4
    test_idomTOOLS->updateTemperatureStats();
320
4
    EXPECT_THAT(TEST_DATA::return_viber_msg,testing::HasSubstr("temperatura maleje"));
321
4
    EXPECT_THAT(TEST_DATA::return_viber_msg,testing::HasSubstr("polu"));
322
4
323
4
    ////////////// rośnie na mieskzaniu
324
4
    TEST_DATA::return_send_to_arduino = "17:12";
325
4
    test_idomTOOLS->updateTemperatureStats();
326
4
    EXPECT_THAT(TEST_DATA::return_viber_msg,testing::HasSubstr("temperatura rośnie"));
327
4
    EXPECT_THAT(TEST_DATA::return_viber_msg,testing::HasSubstr("mieszkaniu"));
328
4
329
4
    ////////////// rośnie na polu
330
4
    TEST_DATA::return_send_to_arduino = "17:17";
331
4
    test_idomTOOLS->updateTemperatureStats();
332
4
    EXPECT_THAT(TEST_DATA::return_viber_msg,testing::HasSubstr("temperatura rośnie"));
333
4
    EXPECT_THAT(TEST_DATA::return_viber_msg,testing::HasSubstr("polu"));
334
4
}
335
336
TEST_F(iDomTOOLS_ClassTest, speakersON_OFF)
337
4
{
338
4
    EXPECT_EQ(test_status.getObjectState("speakers"), STATE::OFF);
339
4
    useful_F::myStaticData->idom_all_state.houseState = STATE::UNLOCK;
340
4
    test_idomTOOLS->turnOnSpeakers();
341
4
    EXPECT_EQ(test_status.getObjectState("speakers"), STATE::ON);
342
4
    test_idomTOOLS->turnOffSpeakers();
343
4
    EXPECT_EQ(test_status.getObjectState("speakers"), STATE::OFF);
344
4
    useful_F::myStaticData->idom_all_state.houseState = STATE::LOCK;
345
4
    test_idomTOOLS->turnOnSpeakers();
346
4
    EXPECT_EQ(test_status.getObjectState("speakers"), STATE::OFF);
347
4
    std::string retStr = useful_F::myStaticData->myEventHandler.run("speakers")->getEvent();
348
4
    EXPECT_THAT(retStr, testing::HasSubstr("speakers can not start due to home state: LOCK"));
349
4
}
350
351
TEST_F(iDomTOOLS_ClassTest, printerON_OFF)
352
4
{
353
4
    useful_F::myStaticData->idom_all_state.houseState = STATE::UNLOCK;
354
4
    test_idomTOOLS->turnOnPrinter();
355
4
    EXPECT_EQ(test_status.getObjectState("printer"), STATE::ON);
356
4
    test_idomTOOLS->turnOffPrinter();
357
4
    EXPECT_EQ(test_status.getObjectState("printer"), STATE::OFF);
358
4
    useful_F::myStaticData->idom_all_state.houseState = STATE::LOCK;
359
4
    test_idomTOOLS->turnOnPrinter();
360
4
    EXPECT_EQ(test_status.getObjectState("printer"), STATE::OFF);
361
4
    std::string retStr = useful_F::myStaticData->myEventHandler.run("230V")->getEvent();
362
4
    EXPECT_THAT(retStr, testing::HasSubstr("Printer can not start due to home state: LOCK"));
363
4
}
364
365
TEST_F(iDomTOOLS_ClassTest, getPinState)
366
4
{
367
4
    setReturnPinState(0);
368
4
    EXPECT_EQ(test_idomTOOLS->getPinState(0), PIN_STATE::LOW_STATE);
369
4
    setReturnPinState(1);
370
4
    EXPECT_EQ(test_idomTOOLS->getPinState(0), PIN_STATE::HIGH_STATE);
371
4
    setReturnPinState(4);
372
4
    EXPECT_EQ(test_idomTOOLS->getPinState(0), PIN_STATE::UNKNOWN_STATE);
373
4
}
374
375
TEST_F(iDomTOOLS_ClassTest, turnOnOffPrinter)
376
4
{
377
4
    useful_F::myStaticData->idom_all_state.houseState = STATE::UNLOCK;
378
4
    test_status.setObjectState("printer",STATE::ON);
379
4
    EXPECT_EQ(test_status.getObjectState("printer"), STATE::ON);
380
4
    setReturnPinState(1);
381
4
    puts("off printer");
382
4
    test_idomTOOLS->turnOnOffPrinter();
383
4
    EXPECT_EQ(test_status.getObjectState("printer"), STATE::OFF);
384
4
    setReturnPinState(0);
385
4
    puts("on printer");
386
4
    test_idomTOOLS->turnOnOffPrinter();
387
4
    EXPECT_EQ(test_status.getObjectState("printer"), STATE::ON);
388
4
    setReturnPinState(4);
389
4
    test_idomTOOLS->turnOnOffPrinter();
390
4
    EXPECT_EQ(test_status.getObjectState("printer"), STATE::ON);
391
4
}
392
393
TEST_F(iDomTOOLS_ClassTest, turn_On_Off_433MHzSwitch)
394
4
{
395
4
    useful_F::myStaticData->idom_all_state.houseState = STATE::UNLOCK;
396
4
    EXPECT_EQ(test_status.getObjectState("B"),STATE::UNKNOWN);
397
4
    test_idomTOOLS->turnOn433MHzSwitch("B");
398
4
    EXPECT_EQ(test_status.getObjectState("B"),STATE::ON);
399
4
    test_idomTOOLS->turnOff433MHzSwitch("B");
400
4
    EXPECT_EQ(test_status.getObjectState("B"),STATE::OFF);
401
4
}
402
403
TEST_F(iDomTOOLS_ClassTest, turn_On_Off_fake_433MHzSwitch)
404
4
{
405
4
    EXPECT_NO_THROW(test_idomTOOLS->turnOn433MHzSwitch("B-fake"));
406
4
    EXPECT_NO_THROW(test_idomTOOLS->turnOff433MHzSwitch("B-fake"));
407
4
    EXPECT_NO_THROW(test_idomTOOLS->turnOnOff433MHzSwitch("B-fake"));
408
4
}
409
410
TEST_F(iDomTOOLS_ClassTest, turnOnOff433MHzSwitch)
411
4
{
412
4
    useful_F::myStaticData->idom_all_state.houseState = STATE::UNLOCK;
413
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("B"),STATE::UNKNOWN);
414
4
    test_my_data.main_iDomStatus->setObjectState("B",STATE::ON);
415
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("B"),STATE::ON);
416
4
    test_idomTOOLS->turnOnOff433MHzSwitch("B");
417
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("B"),STATE::OFF);
418
4
    test_idomTOOLS->turnOnOff433MHzSwitch("B");
419
4
    EXPECT_EQ(test_status.getObjectState("B"),STATE::ON);
420
4
421
4
}
422
423
TEST_F(iDomTOOLS_ClassTest, runOnSunset)
424
4
{
425
4
    useful_F::myStaticData->idom_all_state.houseState = STATE::LOCK;
426
4
    test_idomTOOLS->runOnSunset();
427
4
    std::string retStr = useful_F::myStaticData->myEventHandler.run("iDom")->getEvent();
428
4
    EXPECT_THAT(retStr, testing::HasSubstr("433MHz can not start due to home state: LOCK"));
429
4
430
4
    useful_F::myStaticData->idom_all_state.houseState = STATE::UNLOCK;
431
4
    auto ptr = static_cast<RADIO_SWITCH*>(test_my_data.main_REC->getEqPointer("B"));
432
4
    ptr->m_state = STATE::ON;
433
4
    test_idomTOOLS->runOnSunset();
434
4
435
4
    EXPECT_EQ(test_my_data.main_REC->getEqPointer("B")->getState(), STATE::OFF);
436
4
437
4
    RADIO_EQ_CONFIG cfg;
438
4
    cfg.sunset = "on";
439
4
    cfg.sunrise = "off";
440
4
441
4
    ptr->setCode(cfg);
442
4
    ptr->m_state = STATE::OFF;
443
4
    test_idomTOOLS->runOnSunset();
444
4
445
4
    EXPECT_EQ(test_my_data.main_REC->getEqPointer("B")->getState(), STATE::ON);
446
4
}
447
448
TEST_F(iDomTOOLS_ClassTest, runOnSunrise)
449
4
{
450
4
    useful_F::myStaticData->idom_all_state.houseState = STATE::LOCK;
451
4
    test_idomTOOLS->runOnSunrise();
452
4
    std::string retStr = useful_F::myStaticData->myEventHandler.run("iDom")->getEvent();
453
4
    EXPECT_THAT(retStr, testing::HasSubstr("433MHz can not start due to home state: LOCK"));
454
4
455
4
    useful_F::myStaticData->idom_all_state.houseState = STATE::UNLOCK;
456
4
    auto ptr = static_cast<RADIO_SWITCH*>(test_my_data.main_REC->getEqPointer("B"));
457
4
    ptr->m_state = STATE::OFF;
458
4
    test_idomTOOLS->runOnSunrise();
459
4
460
4
    EXPECT_EQ(test_my_data.main_REC->getEqPointer("B")->getState(), STATE::ON);
461
4
462
4
    RADIO_EQ_CONFIG cfg;
463
4
    cfg.sunset = "off";
464
4
    cfg.sunrise = "on";
465
4
466
4
    ptr->setCode(cfg);
467
4
468
4
    cfg.sunset = "on";
469
4
    cfg.sunrise = "off";
470
4
471
4
    ptr->setCode(cfg);
472
4
    ptr->m_state = STATE::ON;
473
4
    test_idomTOOLS->runOnSunrise();
474
4
475
4
    EXPECT_EQ(test_my_data.main_REC->getEqPointer("B")->getState(), STATE::OFF);
476
4
}
477
478
TEST_F(iDomTOOLS_ClassTest, getSunrise_Sunset)
479
4
{
480
4
    std::string ret = test_idomTOOLS->getSunrise();
481
4
    EXPECT_THAT(ret, testing::HasSubstr(":"));
482
4
483
4
    ret = test_idomTOOLS->getSunset();
484
4
    EXPECT_THAT(ret, testing::HasSubstr(":"));
485
4
486
4
    ret = test_idomTOOLS->getSunrise(true);
487
4
    EXPECT_THAT(ret, testing::HasSubstr("Sunrise time:"));
488
4
489
4
    ret = test_idomTOOLS->getSunset(true);
490
4
    EXPECT_THAT(ret, testing::HasSubstr("Sunset time:"));
491
4
}
492
493
TEST_F(iDomTOOLS_ClassTest, getDayLenght)
494
4
{
495
4
    std::string ret = test_idomTOOLS->getDayLenght();
496
4
    EXPECT_THAT(ret, testing::HasSubstr(":"));
497
4
498
4
    ret = test_idomTOOLS->getDayLenght(true);
499
4
    EXPECT_THAT(ret, testing::HasSubstr("Day Lenght :"));
500
4
}
501
502
TEST_F(iDomTOOLS_ClassTest, getTextToSpeach)
503
4
{
504
4
    TEST_DATA::return_send_to_arduino = "22:23";
505
4
    std::string ret = test_idomTOOLS->getTextToSpeach();
506
4
    EXPECT_THAT(ret, testing::HasSubstr("Smog:"));
507
4
    std::cout << "TEXT :"<< std::endl << ret << std::endl;
508
4
}
509
510
TEST_F(iDomTOOLS_ClassTest, mpd)
511
4
{
512
4
    MPD_info test_ptr_MPD;
513
4
    test_ptr_MPD.volume = 3;
514
4
    test_my_data.ptr_MPD_info = &test_ptr_MPD;
515
4
    blockQueue test_q;
516
4
    test_q._clearAll();
517
4
    useful_F::myStaticData->idom_all_state.houseState = STATE::LOCK;
518
4
    test_idomTOOLS->MPD_play(&test_my_data);
519
4
    std::string retStr = useful_F::myStaticData->myEventHandler.run("MPD")->getEvent();
520
4
    EXPECT_THAT(retStr, testing::HasSubstr("MPD can not start due to home state: LOCK"));
521
4
    EXPECT_EQ(test_q._size(), 0);
522
4
523
4
    useful_F::myStaticData->idom_all_state.houseState = STATE::UNLOCK;
524
4
    test_idomTOOLS->MPD_play(&test_my_data);
525
4
    EXPECT_EQ(test_q._size(), 1);
526
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PLAY);
527
4
    EXPECT_EQ(test_q._size(), 0);
528
4
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
529
4
    useful_F::myStaticData->idom_all_state.houseState = STATE::LOCK;
530
4
531
4
    useful_F::myStaticData->myEventHandler.run("MPD")->clearEvent();
532
4
    test_idomTOOLS->MPD_play(&test_my_data,2);
533
4
    retStr = useful_F::myStaticData->myEventHandler.run("MPD")->getEvent();
534
4
    EXPECT_THAT(retStr, testing::HasSubstr("MPD can not start due to home state: LOCK"));
535
4
    EXPECT_EQ(test_q._size(), 0);
536
4
537
4
    useful_F::myStaticData->idom_all_state.houseState = STATE::UNLOCK;
538
4
    test_idomTOOLS->MPD_play(&test_my_data,2);
539
4
    EXPECT_EQ(test_q._size(), 1);
540
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PLAY_ID);
541
4
    EXPECT_EQ(test_q._size(), 0);
542
4
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
543
4
544
4
    test_idomTOOLS->MPD_stop();
545
4
    EXPECT_EQ(test_q._size(), 1);
546
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::STOP);
547
4
    EXPECT_EQ(test_q._size(), 0);
548
4
549
4
    test_idomTOOLS->MPD_next();
550
4
    EXPECT_EQ(test_q._size(), 1);
551
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::NEXT);
552
4
    EXPECT_EQ(test_q._size(), 0);
553
4
554
4
    test_idomTOOLS->MPD_prev();
555
4
    EXPECT_EQ(test_q._size(), 1);
556
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PREV);
557
4
    EXPECT_EQ(test_q._size(), 0);
558
4
559
4
    test_idomTOOLS->MPD_pause();
560
4
    EXPECT_EQ(test_q._size(), 1);
561
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::PAUSE );
562
4
    EXPECT_EQ(test_q._size(), 0);
563
4
564
4
    test_idomTOOLS->MPD_volumeUp();
565
4
    EXPECT_EQ(test_q._size(), 1);
566
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::VOLUP );
567
4
    EXPECT_EQ(test_q._size(), 0);
568
4
569
4
    test_idomTOOLS->MPD_volumeDown();
570
4
    EXPECT_EQ(test_q._size(), 1);
571
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::VOLDOWN );
572
4
    EXPECT_EQ(test_q._size(), 0);
573
4
574
4
    test_idomTOOLS->MPD_volumeSet(&test_my_data, 99);
575
4
    EXPECT_EQ(test_q._size(), 1);
576
4
    EXPECT_EQ(test_q._get(), MPD_COMMAND::VOLSET );
577
4
    EXPECT_EQ(test_q._size(), 0);
578
4
    EXPECT_EQ(test_my_data.ptr_MPD_info->volume, 99);
579
4
580
4
    EXPECT_EQ(test_idomTOOLS->MPD_getVolume(&test_my_data),99);
581
4
582
4
}
583
584
TEST_F(iDomTOOLS_ClassTest, getTemperatureString)
585
4
{
586
4
    TEST_DATA::return_send_to_arduino = "-2:2";
587
4
    EXPECT_STREQ(test_my_data.main_iDomTools->getTemperatureString().c_str(), "-2:2");
588
4
}
589
590
TEST_F(iDomTOOLS_ClassTest, cameraLED)
591
4
{
592
4
    TEST_DATA::return_httpPost = "ok.\n";
593
4
    test_my_data.main_iDomTools->cameraLedOFF("test_link");
594
4
595
4
    ///////////////////////////////at day
596
4
    Clock::setTime_forBT_usage(12,12);
597
4
    test_my_data.main_iDomTools->cameraLedON("test_link");
598
4
599
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("cameraLED"), STATE::OFF);
600
4
    ////////////////////////////////////// at night
601
4
    Clock::setTime_forBT_usage(2,2);
602
4
    test_my_data.main_iDomTools->cameraLedON("test_link");
603
4
604
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("cameraLED"), STATE::ON);
605
4
}
606
607
TEST_F(iDomTOOLS_ClassTest, textToSpeach)
608
4
{
609
4
    test_my_data.ptr_MPD_info->isPlay = true;
610
4
    test_my_data.main_iDomStatus->setObjectState("speakers", STATE::UNDEFINE);
611
4
612
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("speakers"), STATE::UNDEFINE);
613
4
    std::vector<std::string> test_v;
614
4
    test_my_data.main_iDomTools->textToSpeach(&test_v); //empty
615
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("speakers"), STATE::UNDEFINE);
616
4
617
4
    test_v = {"test","msg","clock"};
618
4
    test_my_data.ptr_MPD_info->isPlay = true;
619
4
    test_my_data.main_iDomTools->textToSpeach(&test_v);
620
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("speakers"), STATE::UNDEFINE);
621
4
    test_my_data.ptr_MPD_info->isPlay = false;
622
4
    test_my_data.main_iDomTools->textToSpeach(&test_v);
623
4
    EXPECT_EQ(test_my_data.main_iDomStatus->getObjectState("speakers"), STATE::OFF);
624
4
}
625
626
TEST_F(iDomTOOLS_ClassTest, getWeatherEvent)
627
4
{
628
4
    TEST_DATA::return_httpPost = "httpPost";
629
4
    std::string retStr = test_my_data.main_iDomTools->getWeatherEvent("test",10);
630
4
    EXPECT_STREQ(retStr.c_str(),"httpPost");
631
4
}
632
633
TEST_F(iDomTOOLS_ClassTest, isItDay)
634
4
{
635
4
    Clock::setTime_forBT_usage(12,12);
636
4
    EXPECT_TRUE(test_my_data.main_iDomTools->isItDay());
637
4
    Clock::setTime_forBT_usage(2,12);
638
4
    EXPECT_FALSE(test_my_data.main_iDomTools->isItDay());
639
4
}
640
641
TEST_F(iDomTOOLS_ClassTest, ledClear)
642
4
{
643
4
    TEST_DATA::return_send_to_arduino = "done";
644
4
    std::string retStr = test_my_data.main_iDomTools->ledClear();
645
4
    EXPECT_STREQ(retStr.c_str(),"done");
646
4
}
647
648
TEST_F(iDomTOOLS_ClassTest, getAllDataSunrisesunset)
649
4
{
650
4
    EXPECT_THAT(test_my_data.main_iDomTools->getAllDataSunrisesunset(),
651
4
                testing::HasSubstr("Days until Y2K"));
652
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/iDomTools/test/lightning_BT.cpp
Line
Count
Source
1
#include <gtest/gtest.h>
2
3
#include "test_data.h"
4
#include "testJSON.h"
5
#include "../idomtools.h"
6
7
class lightning_Class : public ::testing::Test
8
{
9
protected:
10
    TEST_JSON test_Json;
11
    LIGHTNING test_lightning;
12
    CARDINAL_DIRECTIONS::ALARM_INFO test_struct;
13
    virtual void SetUp() final
14
20
    {
15
20
        std::cout << "konfiguracja przed testem lightning_Class " <<std::endl;
16
20
    }
17
18
    virtual void TearDown() final
19
20
    {
20
20
        std::cout << "czyszczenie po tescie lightning_Class " <<std::endl;
21
20
    }
22
};
23
24
TEST_F(lightning_Class, lightningAlertOFF)
25
4
{
26
4
    test_struct = test_lightning.lightningAlert(test_Json.jj_noLightning);
27
4
    std::cout <<std::endl << test_struct.data.str();
28
8
    EXPECT_FALSE(test_struct.riseAlarm) << "BRAK ALARMU";
29
4
}
30
31
TEST_F(lightning_Class, lightningAlertON)
32
4
{
33
4
    test_struct = test_lightning.lightningAlert(test_Json.jj_lightning);
34
4
    std::cout <<std::endl << test_struct.data.str();
35
8
    EXPECT_TRUE(test_struct.riseAlarm) << "BRAK ALARMU";
36
4
}
37
38
TEST_F(lightning_Class, checkLightningAlert)
39
4
{
40
4
41
4
    nlohmann::json test_Json2 = useful_F_libs::getJson("http://cyniu88.no-ip.pl/test/json/on_lightning.json");
42
4
    test_struct = test_lightning.lightningAlert(test_Json.jj_noLightning);
43
4
44
4
    bool test_result = test_lightning.checkLightningAlert(&test_struct);
45
4
46
8
    EXPECT_FALSE(test_result) << "BRAK ALARMU 1";
47
4
    test_struct = test_lightning.lightningAlert(test_Json2);
48
4
    test_result = test_lightning.checkLightningAlert(&test_struct);
49
8
    EXPECT_TRUE(test_result) << "BRAK ALARMU 2";
50
4
    test_result = test_lightning.checkLightningAlert(&test_struct);
51
8
    EXPECT_FALSE(test_result) << "BRAK ALARMU 3";
52
4
    test_struct.riseAlarm = false;
53
4
    test_result = test_lightning.checkLightningAlert(&test_struct);
54
8
    EXPECT_FALSE(test_result) << "BRAK ALARMU 4";
55
4
    test_struct.riseAlarm = false;
56
4
    test_result = test_lightning.checkLightningAlert(&test_struct);
57
8
    EXPECT_FALSE(test_result) << "BRAK ALARMU 5";
58
4
}
59
60
TEST_F(lightning_Class, checkLightningAlert_stormCloser)
61
4
{
62
4
    nlohmann::json test_Json2 = useful_F_libs::getJson("http://cyniu88.no-ip.pl/test/json/on_lightning.json");
63
4
64
4
    test_struct = test_lightning.lightningAlert(test_Json.jj_noLightning);
65
4
    bool test_result = test_lightning.checkLightningAlert(&test_struct);
66
8
    EXPECT_FALSE(test_result) << "BRAK ALARMU 1";
67
4
68
4
    test_struct = test_lightning.lightningAlert(test_Json2);
69
4
    test_result = test_lightning.checkLightningAlert(&test_struct);
70
8
    EXPECT_TRUE(test_result) << "BRAK ALARMU 2";
71
4
72
4
    test_result = test_lightning.checkLightningAlert(&test_struct);
73
8
    EXPECT_FALSE(test_result) << "BRAK ALARMU 3";
74
4
75
4
    test_struct = test_lightning.lightningAlert(test_Json.jj_lightning_lt15km);
76
4
    test_result = test_lightning.checkLightningAlert(&test_struct);
77
8
    EXPECT_TRUE(test_result) << "BRAK ALARMU 4";
78
4
79
4
    test_struct = test_lightning.lightningAlert(test_Json.jj_lightning_lt15km);
80
4
    test_result = test_lightning.checkLightningAlert(&test_struct);
81
8
    EXPECT_FALSE(test_result) << "BRAK ALARMU 5";
82
4
83
4
    test_struct = test_lightning.lightningAlert(test_Json.jj_noLightning);
84
4
    test_result = test_lightning.checkLightningAlert(&test_struct);
85
8
    EXPECT_FALSE(test_result) << "BRAK ALARMU 6";
86
4
87
4
    test_struct = test_lightning.lightningAlert(test_Json.jj_lightning_lt15km);
88
4
    test_result = test_lightning.checkLightningAlert(&test_struct);
89
8
    EXPECT_TRUE(test_result) << "BRAK ALARMU 7";
90
4
}
91
92
TEST_F(lightning_Class, oneLightning)
93
4
{
94
4
    test_struct = test_lightning.lightningAlert(test_Json.jj_oneLightning);
95
4
    bool test_result = test_lightning.checkLightningAlert(&test_struct);
96
4
    EXPECT_FALSE(test_result);
97
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/iDom_server_OOP.h
Line
Count
Source
1
#ifndef GLOBAL_H
2
#define GLOBAL_H
3
4
#include <iostream>
5
#include <fstream>
6
#include <string>
7
#include <cstdlib>
8
#include <pthread.h>
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <sys/socket.h>
12
#include <sys/types.h>
13
#include <netinet/in.h>
14
#include <vector>
15
#include <thread>
16
#include <arpa/inet.h>
17
#include <netinet/in.h>
18
#include <unistd.h>
19
#include <sys/fcntl.h>
20
#include <unistd.h>
21
#include <errno.h>
22
#include <signal.h>
23
#include <time.h>
24
#include <wiringPi.h>
25
#include <chrono>
26
#include <array>
27
28
// MOJE BIBLIOTEKI
29
#include "KEY/key.h"
30
#include "logger/logger.hpp"
31
#include "files_tree/files_tree.h"
32
#include "menu_tree/menu_tree.h"
33
#include "LCD_c/lcd_c.h"
34
#include "command/command.h"
35
#include "../libs/event_counters/event_counters_handler.h"
36
#include "iDomTools/idomtools.h"
37
#include "iDomStatus/idomstatus.h"
38
#include "iDomSaveState/idom_save_state.h"
39
40
2.04k
#define log_file_cout  f_log //std::cout zmien f_log na std::cout i bedzie wypisywac na ekran
41
850
#define log_file_mutex f_log
42
43
enum class iDomStateEnum{
44
    CLOSE = 0,
45
    RELOAD,
46
    ERROR,
47
    WORKING,
48
    HARD_RELOAD
49
};
50
51
namespace iDomConst
52
{
53
constexpr int MAX_CONNECTION = 10;
54
constexpr int FREE  = 1;
55
constexpr int RS232 = 11;
56
constexpr int CLOCK = 12;
57
constexpr int ok    = 0;
58
constexpr int GPIO_SPIK = 21;
59
constexpr int GPIO_PRINTER = 22;
60
}
61
struct ALERT
62
{
63
    Clock time;
64
    STATE state = STATE::DEACTIVE;
65
    unsigned int fromVolume = 48;
66
    unsigned int toVolume = 58;
67
    unsigned int radioID = 8;
68
};
69
70
extern std::string _logfile;
71
extern Logger log_file_mutex;
72
extern std::string buffer;
73
74
enum class TEMPERATURE_STATE;
75
enum class PILOT_KEY;
76
77
struct MPD_info{
78
    std::string title   = "NULL";
79
    std::string radio   = "NULL";
80
    std::string artist  = "NULL";
81
    int volume = 0;
82
    bool isPlay = false;
83
    int currentSongID = 0;
84
    std::vector <std::string> songList = {"NULL"};
85
};
86
struct s_pointer{
87
    unsigned int *ptr_who;
88
    int32_t *ptr_buf;
89
};
90
91
struct Thread_array_struc {
92
    std::thread thread;
93
    std::thread::id thread_ID = std::thread::id(0);
94
    std::string thread_name;
95
    int thread_socket = 0;
96
};
97
98
struct address_another_servers {
99
    int id;
100
    std::string SERVER_IP;
101
};
102
103
struct FTP_SERVER{
104
    std::string URL;
105
    std::string user;
106
    std::string pass;
107
};
108
struct iDOM_STATE{
109
    STATE houseState = STATE::UNDEFINE;
110
111
};
112
113
struct config{
114
    std::string portRS232;
115
    std::string portRS232_clock;
116
    std::string BaudRate;
117
    std::string RFLinkPort;
118
    std::string RFLinkBaudRate;
119
    int PORT;
120
    std::string SERVER_IP;
121
    std::string MPD_IP;
122
    std::string MOVIES_DB_PATH;
123
    std::string MENU_PATH;
124
    std::string THREAD_MPD   = "NULL";
125
    std::string THREAD_IRDA  = "NULL";
126
    std::string THREAD_CRON  = "NULL";
127
    std::string THREAD_RS232 = "NULL";
128
    std::string THREAD_DUMMY = "NULL";
129
    std::string TS_KEY= " gg ";
130
    std::string cameraLedON = "";
131
    std::string cameraLedOFF ="";
132
    std::string cameraURL="";
133
    std::string facebookAccessToken = "";
134
    std::string viberToken = "NULL";
135
    std::string viberAvatar;
136
    std::vector <std::string> viberReceiver;
137
    std::string viberSender;
138
    std::string radio433MHzConfigFile;
139
    std::string omxplayerFile = "NULL";
140
    int ID_server = 0;
141
    int v_delay;
142
    bool encrypted = true;
143
144
    FTP_SERVER ftpServer;
145
    std::string lightningApiURL = "NULL";
146
    std::string saveFilePath = "NULL";
147
};
148
149
struct LED_Strip{
150
    std::string from;
151
    std::string to;
152
    std::string R;
153
    std::string G;
154
    std::string B;
155
    std::string colorName;
156
157
    LED_Strip (int from, int to, int r, int g, int b, std::string colorName = "NULL"):from(std::to_string(from)),
158
        to(std::to_string(to)),
159
        R(std::to_string(r)),
160
        G(std::to_string(g)),
161
        B(std::to_string(b)),
162
        colorName(colorName)
163
6.35k
    {
164
6.35k
165
6.35k
    }
166
    LED_Strip (const std::string& from,
167
               const std::string& to,
168
               const std::string& r,
169
               const std::string& g,
170
               const std::string& b,
171
               const std::string& colorName = "NULL"):
172
        from(from),
173
        to(to),
174
        R(r),
175
        G(g),
176
        B(b),
177
        colorName(colorName)
178
4
    {
179
4
180
4
    }
181
182
    void set (const std::string& from,
183
              const std::string& to,
184
              const std::string& r,
185
              const std::string& g,
186
              const std::string& b,
187
              const std::string& colorName = "NULL")
188
4
    {
189
4
        this->from =from;
190
4
        this->to = to;
191
4
        R = r;
192
4
        G = g;
193
4
        B = b;
194
4
        this->colorName =colorName;
195
4
    }
196
197
4
    void set (int from, int to, int r, int g, int b, std::string colorName = "NULL"){
198
4
        this->from = std::to_string(from);
199
4
        this->to = std::to_string(to);
200
4
        R = std::to_string(r);
201
4
        G = std::to_string(g);
202
4
        B = std::to_string(b);
203
4
        this->colorName =colorName;
204
4
    }
205
206
48
    std::string getColorName() const{
207
48
        return colorName;
208
48
    }
209
210
76
    std::string get(unsigned int _from, unsigned int _to) const{
211
76
        if (_from != 0 || _to != 60){
212
40
            return "LED:["+std::to_string(_from)+"-"+std::to_string(_to)+"-"+R+"-"+G+"-"+B+"];";
213
40
        }
214
36
        return "LED:["+from+"-"+to+"-"+R+"-"+G+"-"+B+"];";
215
36
    }
216
217
    std::string makeCommand(const std::string& from,
218
                            const std::string& to,
219
                            const std::string& R,
220
                            const std::string& G,
221
4
                            const std::string& B){
222
4
        return "LED:["+from+"-"+to+"-"+R+"-"+G+"-"+B+"];";
223
4
    }
224
};
225
226
struct pilot_led{
227
    unsigned int counter=0;
228
    std::vector<LED_Strip> colorLED   = { LED_Strip(1,60,237,145,33 ,"carrot orange"),
229
                                          LED_Strip(1,60,255,0,0    ,"red"),
230
                                          LED_Strip(1,60,0,255,0    ,"green"),
231
                                          LED_Strip(1,60,0,0,255    ,"blue"),
232
                                          LED_Strip(1,60,255,255,255,"white"),
233
                                          LED_Strip(1,60,255,255,0  ,"yellow"),
234
                                          LED_Strip(1,60,0,255,255  ,"cyan"),
235
                                          LED_Strip(1,60,255,0,255  ,"magenta")
236
                                        };
237
};
238
239
class command; // for struc thread_data req
240
class iDomTOOLS;
241
class RADIO_EQ_CONTAINER;
242
class RFLinkHandler;
243
244
struct thread_data{
245
    int s_client_sock;
246
    struct sockaddr_in from;
247
    struct config *server_settings = NULL;
248
    struct s_pointer pointer;
249
    LCD_c *mainLCD = NULL;
250
    files_tree *main_tree = NULL;
251
    menu_tree *main_MENU = NULL;
252
    iDomTOOLS *main_iDomTools = NULL;
253
    RFLinkHandler *main_RFLink = NULL;
254
    std::array<Thread_array_struc, iDomConst::MAX_CONNECTION> *main_THREAD_arr = NULL;
255
    time_t start;
256
    time_t now_time;
257
    int sleeper;
258
    std::map <std::string, std::unique_ptr <KEY> > key_map;
259
    MPD_info *ptr_MPD_info = NULL;
260
    pilot_led * ptr_pilot_led = NULL;
261
    std::map <std::string, std::unique_ptr<command> >* commandMapPtr = NULL;
262
    event_counters_handler myEventHandler;
263
    std::string encriptionKey = "40%";
264
    iDomSTATUS *main_iDomStatus;
265
    iDOM_STATE idom_all_state;
266
    ALERT alarmTime;
267
    std::shared_ptr<RADIO_EQ_CONTAINER> main_REC;
268
    iDomStateEnum iDomProgramState = iDomStateEnum::WORKING;
269
};
270
271
struct thread_data_rs232{
272
    std::string portRS232;
273
    std::string portRS232_clock;
274
    std::string BaudRate;
275
    struct s_pointer pointer;
276
};
277
278
#endif // GLOBAL_H
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/logger/logger.cc
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * logger.cc
3
 *
4
 *
5
 * Logger Library
6
 *
7
 *
8
 * Copyright (C) 2013-2014  Bryant Moscon - bmoscon@gmail.com
9
 * 
10
 * Permission is hereby granted, free of charge, to any person obtaining a copy
11
 * of this software and associated documentation files (the "Software"), to 
12
 * deal in the Software without restriction, including without limitation the 
13
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
14
 * sell copies of the Software, and to permit persons to whom the Software is
15
 * furnished to do so, subject to the following conditions:
16
 *
17
 * 1. Redistributions of source code must retain the above copyright notice, 
18
 *    this list of conditions, and the following disclaimer.
19
 *
20
 * 2. Redistributions in binary form must reproduce the above copyright notice, 
21
 *    this list of conditions and the following disclaimer in the documentation 
22
 *    and/or other materials provided with the distribution, and in the same 
23
 *    place and form as other copyright, license and disclaimer information.
24
 *
25
 * 3. The end-user documentation included with the redistribution, if any, must 
26
 *    include the following acknowledgment: "This product includes software 
27
 *    developed by Bryant Moscon (http://www.bryantmoscon.org/)", in the same 
28
 *    place and form as other third-party acknowledgments. Alternately, this 
29
 *    acknowledgment may appear in the software itself, in the same form and 
30
 *    location as other such third-party acknowledgments.
31
 *
32
 * 4. Except as contained in this notice, the name of the author, Bryant Moscon,
33
 *    shall not be used in advertising or otherwise to promote the sale, use or 
34
 *    other dealings in this Software without prior written authorization from 
35
 *    the author.
36
 *
37
 *
38
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
39
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
40
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
41
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
42
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
44
 * THE SOFTWARE.
45
 *
46
 */
47
48
#include "logger.hpp"
49
50
pthread_mutex_t Logger::mutex_log = PTHREAD_MUTEX_INITIALIZER;
51
52
Logger::Logger(const char *f) : _file(f, std::ios::out | std::ios::app), 
53
        _log(_file),
54
        _level(INFO),
55
        _line_level(VERBOSE)
56
0
{
57
0
  assert(_file.is_open());
58
0
}
Unexecuted instantiation: _ZN6LoggerC2EPKc
Unexecuted instantiation: _ZN6LoggerC1EPKc
59
60
61
Logger::Logger(const std::string& f) : _file(f.c_str(), std::ios::out | std::ios::app), 
62
               _log(_file),
63
               _level(INFO),
64
               _line_level(VERBOSE)
65
1
{
66
1
  assert(_file.is_open());
67
1
}
Unexecuted instantiation: _ZN6LoggerC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
_ZN6LoggerC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Line
Count
Source
65
1
{
66
1
  assert(_file.is_open());
67
1
}
68
69
70
Logger::~Logger()
71
0
{
72
0
  if (_file.is_open()) {
73
0
    _log.flush();
74
0
    _file.close();
75
0
  }
76
0
}
77
78
void Logger::set_level(const logger_level& level)
79
0
{
80
0
  _level = level;
81
0
}  
82
 
83
84
void Logger::flush()
85
426
{
86
426
  if (_line_level >= _level) {
87
389
    _log << get_time() << " -- [" << level_str(_line_level) << "] -- " << str();
88
389
    _log.flush();
89
389
  }
90
37
  else
91
37
  {
92
37
      _log << get_time() << " -- [" << level_str(_line_level) << "] -- " << str();
93
37
      _log.flush();
94
37
  }
95
426
96
426
  str("");
97
426
  _line_level = VERBOSE;
98
426
}
99
100
101
Logger& Logger::operator<<(const logger_level& level)
102
421
{
103
421
  _line_level = level;
104
421
  return (*this);
105
421
}
106
107
108
Logger& Logger::operator<<(LoggerManip m)
109
426
{ 
110
426
  return m(*this);
111
426
}
112
113
114
std::string Logger::get_time() const
115
426
{
116
426
  struct tm *timeinfo;
117
426
  time_t rawtime;
118
426
  char *time_buf;
119
426
  
120
426
  time(&rawtime);
121
426
  timeinfo = localtime(&rawtime);
122
426
  time_buf = asctime(timeinfo);
123
426
  
124
426
  std::string ret(time_buf);
125
426
  if (!ret.empty() && ret[ret.length() - 1] == '\n') {
126
426
    ret.erase(ret.length()-1);
127
426
  }
128
426
  
129
426
  return (ret);
130
426
}
131
132
133
inline const char* Logger::level_str(const logger_level& level)
134
426
{
135
426
  switch (level) {
136
426
  case VERBOSE:
137
13
    return ("VERBOSE ");
138
426
  case DEBUG:
139
24
    return (" DEBUG  ");
140
426
  case INFO:
141
241
    return ("  INFO  ");
142
426
  case WARNING:
143
24
    return ("WARNING ");
144
426
  case ERROR:
145
64
    return (" ERROR  ");
146
426
  case CRITICAL:
147
56
    return ("CRITICAL");
148
426
  case FATAL:
149
4
    return (" FATAL  ");
150
426
  default:
151
0
    assert(false);
152
426
  } 
153
426
}
154
void Logger::mutex_lock()
155
421
{
156
421
    pthread_mutex_lock(&Logger::mutex_log);
157
421
}
158
159
void Logger::mutex_unlock()
160
421
{
161
421
    pthread_mutex_unlock(&Logger::mutex_log);
162
421
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/logger/logger.hpp
Line
Count
Source
1
/*
2
 * logger.hpp
3
 *
4
 *
5
 * Logger Library Header
6
 *
7
 *
8
 * Copyright (C) 2013-2014  Bryant Moscon - bmoscon@gmail.com
9
 *
10
 * Permission is hereby granted, free of charge, to any person obtaining a copy
11
 * of this software and associated documentation files (the "Software"), to
12
 * deal in the Software without restriction, including without limitation the
13
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
14
 * sell copies of the Software, and to permit persons to whom the Software is
15
 * furnished to do so, subject to the following conditions:
16
 *
17
 * 1. Redistributions of source code must retain the above copyright notice,
18
 *    this list of conditions, and the following disclaimer.
19
 *
20
 * 2. Redistributions in binary form must reproduce the above copyright notice,
21
 *    this list of conditions and the following disclaimer in the documentation
22
 *    and/or other materials provided with the distribution, and in the same
23
 *    place and form as other copyright, license and disclaimer information.
24
 *
25
 * 3. The end-user documentation included with the redistribution, if any, must
26
 *    include the following acknowledgment: "This product includes software
27
 *    developed by Bryant Moscon (http://www.bryantmoscon.org/)", in the same
28
 *    place and form as other third-party acknowledgments. Alternately, this
29
 *    acknowledgment may appear in the software itself, in the same form and
30
 *    location as other such third-party acknowledgments.
31
 *
32
 * 4. Except as contained in this notice, the name of the author, Bryant Moscon,
33
 *    shall not be used in advertising or otherwise to promote the sale, use or
34
 *    other dealings in this Software without prior written authorization from
35
 *    the author.
36
 *
37
 *
38
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
41
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44
 * THE SOFTWARE.
45
 *
46
 */
47
#ifndef __LOGGER__
48
#define __LOGGER__
49
50
#include <fstream>
51
#include <cassert>
52
#include <ctime>
53
#include <sstream>
54
55
// Log levels
56
typedef enum {
57
    US =0,
58
    VERBOSE,
59
    DEBUG,
60
    INFO,
61
    WARNING,
62
    ERROR,
63
    CRITICAL,
64
    FATAL
65
} logger_level;
66
67
class Logger : public std::ostringstream {
68
public:
69
70
    explicit Logger(const char *f);
71
    explicit Logger(const std::string& f);
72
    Logger (const Logger &);
73
    Logger &operator= (const Logger &);
74
    ~Logger();
75
    static pthread_mutex_t mutex_log;
76
77
    void set_level(const logger_level& level);
78
    void flush();
79
    void mutex_lock();
80
    void mutex_unlock();
81
82
    template <typename T>
83
    Logger& operator<<(const T& t)
84
766
    {
85
766
        *static_cast<std::ostringstream *>(this) << t;
86
766
        return (*this);
87
766
    }
_ZN6LoggerlsIA45_cEERS_RKT_
Line
Count
Source
84
5
    {
85
5
        *static_cast<std::ostringstream *>(this) << t;
86
5
        return (*this);
87
5
    }
_ZN6LoggerlsIA10_cEERS_RKT_
Line
Count
Source
84
1
    {
85
1
        *static_cast<std::ostringstream *>(this) << t;
86
1
        return (*this);
87
1
    }
_ZN6LoggerlsINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEERS_RKT_
Line
Count
Source
84
364
    {
85
364
        *static_cast<std::ostringstream *>(this) << t;
86
364
        return (*this);
87
364
    }
_ZN6LoggerlsIA36_cEERS_RKT_
Line
Count
Source
84
12
    {
85
12
        *static_cast<std::ostringstream *>(this) << t;
86
12
        return (*this);
87
12
    }
_ZN6LoggerlsIA37_cEERS_RKT_
Line
Count
Source
84
20
    {
85
20
        *static_cast<std::ostringstream *>(this) << t;
86
20
        return (*this);
87
20
    }
_ZN6LoggerlsIA43_cEERS_RKT_
Line
Count
Source
84
4
    {
85
4
        *static_cast<std::ostringstream *>(this) << t;
86
4
        return (*this);
87
4
    }
_ZN6LoggerlsIA30_cEERS_RKT_
Line
Count
Source
84
8
    {
85
8
        *static_cast<std::ostringstream *>(this) << t;
86
8
        return (*this);
87
8
    }
_ZN6LoggerlsIA31_cEERS_RKT_
Line
Count
Source
84
12
    {
85
12
        *static_cast<std::ostringstream *>(this) << t;
86
12
        return (*this);
87
12
    }
_ZN6LoggerlsIA39_cEERS_RKT_
Line
Count
Source
84
8
    {
85
8
        *static_cast<std::ostringstream *>(this) << t;
86
8
        return (*this);
87
8
    }
_ZN6LoggerlsIA65_cEERS_RKT_
Line
Count
Source
84
4
    {
85
4
        *static_cast<std::ostringstream *>(this) << t;
86
4
        return (*this);
87
4
    }
_ZN6LoggerlsIA55_cEERS_RKT_
Line
Count
Source
84
4
    {
85
4
        *static_cast<std::ostringstream *>(this) << t;
86
4
        return (*this);
87
4
    }
_ZN6LoggerlsIA56_cEERS_RKT_
Line
Count
Source
84
4
    {
85
4
        *static_cast<std::ostringstream *>(this) << t;
86
4
        return (*this);
87
4
    }
_ZN6LoggerlsIA32_cEERS_RKT_
Line
Count
Source
84
24
    {
85
24
        *static_cast<std::ostringstream *>(this) << t;
86
24
        return (*this);
87
24
    }
_ZN6LoggerlsIA28_cEERS_RKT_
Line
Count
Source
84
16
    {
85
16
        *static_cast<std::ostringstream *>(this) << t;
86
16
        return (*this);
87
16
    }
_ZN6LoggerlsIA47_cEERS_RKT_
Line
Count
Source
84
4
    {
85
4
        *static_cast<std::ostringstream *>(this) << t;
86
4
        return (*this);
87
4
    }
_ZN6LoggerlsIA24_cEERS_RKT_
Line
Count
Source
84
4
    {
85
4
        *static_cast<std::ostringstream *>(this) << t;
86
4
        return (*this);
87
4
    }
Unexecuted instantiation: _ZN6LoggerlsIA44_cEERS_RKT_
_ZN6LoggerlsIA23_cEERS_RKT_
Line
Count
Source
84
16
    {
85
16
        *static_cast<std::ostringstream *>(this) << t;
86
16
        return (*this);
87
16
    }
_ZN6LoggerlsIA14_cEERS_RKT_
Line
Count
Source
84
24
    {
85
24
        *static_cast<std::ostringstream *>(this) << t;
86
24
        return (*this);
87
24
    }
Unexecuted instantiation: _ZN6LoggerlsIA27_cEERS_RKT_
Unexecuted instantiation: _ZN6LoggerlsIiEERS_RKT_
_ZN6LoggerlsIA22_cEERS_RKT_
Line
Count
Source
84
16
    {
85
16
        *static_cast<std::ostringstream *>(this) << t;
86
16
        return (*this);
87
16
    }
_ZN6LoggerlsIA2_cEERS_RKT_
Line
Count
Source
84
32
    {
85
32
        *static_cast<std::ostringstream *>(this) << t;
86
32
        return (*this);
87
32
    }
_ZN6LoggerlsIA7_cEERS_RKT_
Line
Count
Source
84
16
    {
85
16
        *static_cast<std::ostringstream *>(this) << t;
86
16
        return (*this);
87
16
    }
_ZN6LoggerlsINSt6thread2idEEERS_RKT_
Line
Count
Source
84
16
    {
85
16
        *static_cast<std::ostringstream *>(this) << t;
86
16
        return (*this);
87
16
    }
_ZN6LoggerlsIA26_cEERS_RKT_
Line
Count
Source
84
12
    {
85
12
        *static_cast<std::ostringstream *>(this) << t;
86
12
        return (*this);
87
12
    }
_ZN6LoggerlsIA3_cEERS_RKT_
Line
Count
Source
84
4
    {
85
4
        *static_cast<std::ostringstream *>(this) << t;
86
4
        return (*this);
87
4
    }
Unexecuted instantiation: _ZN6LoggerlsIPKcEERS_RKT_
_ZN6LoggerlsIA15_cEERS_RKT_
Line
Count
Source
84
52
    {
85
52
        *static_cast<std::ostringstream *>(this) << t;
86
52
        return (*this);
87
52
    }
_ZN6LoggerlsIA29_cEERS_RKT_
Line
Count
Source
84
8
    {
85
8
        *static_cast<std::ostringstream *>(this) << t;
86
8
        return (*this);
87
8
    }
_ZN6LoggerlsIA25_cEERS_RKT_
Line
Count
Source
84
8
    {
85
8
        *static_cast<std::ostringstream *>(this) << t;
86
8
        return (*this);
87
8
    }
_ZN6LoggerlsIPcEERS_RKT_
Line
Count
Source
84
4
    {
85
4
        *static_cast<std::ostringstream *>(this) << t;
86
4
        return (*this);
87
4
    }
_ZN6LoggerlsIA16_cEERS_RKT_
Line
Count
Source
84
12
    {
85
12
        *static_cast<std::ostringstream *>(this) << t;
86
12
        return (*this);
87
12
    }
_ZN6LoggerlsIbEERS_RKT_
Line
Count
Source
84
8
    {
85
8
        *static_cast<std::ostringstream *>(this) << t;
86
8
        return (*this);
87
8
    }
_ZN6LoggerlsIA20_cEERS_RKT_
Line
Count
Source
84
8
    {
85
8
        *static_cast<std::ostringstream *>(this) << t;
86
8
        return (*this);
87
8
    }
_ZN6LoggerlsIA8_cEERS_RKT_
Line
Count
Source
84
32
    {
85
32
        *static_cast<std::ostringstream *>(this) << t;
86
32
        return (*this);
87
32
    }
_ZN6LoggerlsIA21_cEERS_RKT_
Line
Count
Source
84
4
    {
85
4
        *static_cast<std::ostringstream *>(this) << t;
86
4
        return (*this);
87
4
    }
88
89
    Logger& operator<<(const logger_level& level);
90
    typedef Logger& (* LoggerManip)(Logger&);
91
    Logger& operator<<(LoggerManip m);
92
93
private:
94
    std::string get_time() const;
95
    inline const char* level_str(const logger_level& level);
96
public:
97
    std::ofstream _file;
98
private:
99
    std::ostream& _log;
100
    logger_level _level;
101
    logger_level _line_level;
102
};
103
104
105
namespace std { 
106
inline Logger& endl(Logger& out)
107
426
{
108
426
    out.put('\n');
109
426
    out.flush();
110
426
    return (out);
111
426
}
112
}// end namespace std
113
114
#endif
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/menu_tree/menu_tree.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "menu_tree.h"
2
3
menu_tree::menu_tree (const std::string &path, LCD_c *mainLCD_PTR):database_path(path),w_serial( "([Ss]\\d{1,3}[Ee]\\d{1,3})")
4
48
{
5
48
    mainLCD=mainLCD_PTR;
6
48
7
48
    i_stack.push(0);
8
48
    i=0;
9
48
    get_list(database_path);
10
48
}
11
12
bool menu_tree::is_file() const
13
28
{
14
28
    return movie_database_vector[i].is_file;
15
28
}
16
//std::string menu_tree::return_path( int i) const
17
//{
18
19
//    return movie_database_vector[i].path;
20
//}
21
22
//void menu_tree::get_main_list()
23
//{
24
//    get_list( database_path );
25
//}
26
void menu_tree::next()
27
92
{   
28
92
    ++i;
29
92
    if (get_vector_size() == i ){
30
8
        i=0;
31
8
    }
32
92
}
33
34
void menu_tree::previous()
35
24
{
36
24
    --i;
37
24
    if ( i <0 )
38
4
    {
39
4
        i = get_vector_size()-1;
40
4
    }
41
24
}
42
43
int menu_tree::get_vector_size () const
44
96
{
45
96
    return static_cast<int>(movie_database_vector.size());
46
96
}
47
void menu_tree::vector_clear ()
48
56
{
49
56
    movie_database_vector.clear();
50
56
}
51
int menu_tree::get_i()
52
4
{
53
4
    if (i_stack.size() >1 ) {
54
4
        int i = i_stack.top();
55
4
        i_stack.pop();
56
4
        return i;
57
4
    }
58
0
    else
59
0
        return 0;
60
4
}
61
62
void menu_tree::enter_dir()
63
4
{
64
4
    i_stack.push(i); // wpisuje na stos kolejna wersje licznika i
65
4
    
66
4
    if (movie_database_vector[i].is_file == true ) {
67
0
68
0
    }
69
4
    else {
70
4
        get_list (movie_database_vector[i].path);
71
4
        i=0;
72
4
    }
73
4
}
74
75
void menu_tree::back_dir()
76
4
{
77
4
    if ( tree_stack.size() >1 ) {
78
4
        tree_stack.pop();
79
4
        std::string path = tree_stack.top();
80
4
        tree_stack.pop();
81
4
        i = get_i();
82
4
        get_list (path);
83
4
        return;
84
4
    }
85
0
    i = get_i();
86
0
    get_list (database_path);
87
0
    return;
88
0
}
89
90
std::string menu_tree::show_list()
91
240
{
92
240
    if (movie_database_vector.at(i).is_file == true ) {
93
168
        mainLCD->printString(true,0,0,movie_database_vector[i].files_name.substr(0,16));
94
168
95
168
        return movie_database_vector[i].files_name;
96
168
    }
97
72
    else {
98
72
        mainLCD->printString(true,0,0,movie_database_vector[i].files_name+" ->");
99
72
    }
100
240
101
240
    return movie_database_vector[i].path;
102
240
}
103
bool comper (const movie_database & a , const movie_database& b);
104
//{
105
//    return a.files_name < b.files_name;
106
//}
107
108
56
void menu_tree::get_list(std::string path) {
109
56
    tree_stack.push(path);
110
56
    vector_clear(); // czyscimy vector
111
56
    std::string path2;
112
56
    std::string v_path ,tmp_string;
113
56
    if(sciezka = opendir( path.c_str() )) {
114
56
115
56
116
432
        while(( plik = readdir( sciezka ) ) )
117
376
        {
118
376
            path2 = path;
119
376
            if (static_cast<int>(plik->d_type) == 4 /*&& strcmp( plik->d_name, "..") && strcmp( plik->d_name, ".")*/ )
120
216
            {
121
216
                if (!strcmp( plik->d_name, "..") || !strcmp( plik->d_name, "."))
122
112
                {continue;}
123
104
                temp.is_file=false;
124
104
            }
125
160
            else //if ( (int)plik->d_type == 8 && strcmp( plik->d_name, "..") && strcmp( plik->d_name, "."))
126
160
            {
127
160
                temp.is_file=true;
128
160
            }
129
376
130
376
            v_path= path2;
131
264
            v_path+="/";
132
264
            tmp_string.assign(plik->d_name);
133
264
            v_path+=tmp_string;
134
264
            temp.path =v_path;
135
264
            temp.files_name.assign(plik->d_name);
136
264
            movie_database_vector.push_back(temp);
137
264
138
264
        } // end while
139
56
        sort(movie_database_vector.begin(),movie_database_vector.end(), comper);
140
56
        closedir( sciezka );
141
56
    }
142
56
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/thread_functions/TEST/rs232_thread_BT.cpp
Line
Count
Source
1
#include <gtest/gtest.h>
2
#include "../../iDom_server_OOP.h"
3
#include "../rs232_thread.h"
4
#include "test_data.h"
5
#include "../../../iDom_server_OOP/src/iDomTools/test/iDomTools_fixture.h"
6
7
std::mutex useful_F::mutex_buf;
8
std::mutex useful_F::mutex_who;
9
10
std::string buffer;
11
12
class rs232_thread_fixture : public iDomTOOLS_ClassTest
13
{
14
15
};
16
17
TEST_F(rs232_thread_fixture, send_Recieve_rs232_thread_fixture_clock)
18
4
{
19
4
    useful_F::go_while = true;
20
4
    EXPECT_EQ(useful_F::myStaticData->myEventHandler.run("RS232")->howManyEvent(), 0);
21
4
    thread_data_rs232 test_data_rs232;
22
4
    test_data_rs232.BaudRate = "9600";
23
4
    test_data_rs232.portRS232 = "test_port";
24
4
    test_data_rs232.portRS232_clock = "test_port_clock";
25
4
    unsigned int wh[2];
26
4
    test_data_rs232.pointer.ptr_who = wh;
27
4
    test_data_rs232.pointer.ptr_who[0] = iDomConst::CLOCK;
28
4
    test_data_rs232.pointer.ptr_who[1] = iDomConst::FREE;
29
4
    EXPECT_EQ(test_data_rs232.pointer.ptr_who[1], iDomConst::FREE);
30
4
31
4
    SerialPi_set_recv_msg("OK");
32
4
    EXPECT_STREQ(TEST_DATA::serial_b.c_str(),"OK");
33
4
    Send_Recieve_rs232_thread(&test_data_rs232,"RS232_THREAD");
34
4
35
4
    EXPECT_STREQ(TEST_DATA::serial_b.c_str(),"");
36
4
    EXPECT_EQ(test_data_rs232.pointer.ptr_who[1], iDomConst::CLOCK);
37
4
    EXPECT_EQ(useful_F::myStaticData->myEventHandler.run("RS232")->howManyEvent(), 0);
38
4
}
39
40
TEST_F(rs232_thread_fixture, send_Recieve_rs232_thread_clock_empty_answer)
41
4
{
42
4
    useful_F::go_while = true;
43
4
    thread_data_rs232 test_data_rs232;
44
4
    test_data_rs232.BaudRate = "9600";
45
4
    test_data_rs232.portRS232 = "test_port";
46
4
    test_data_rs232.portRS232_clock = "test_port_clock";
47
4
    unsigned int test_who[2] = {iDomConst::CLOCK, iDomConst::FREE};
48
4
    EXPECT_EQ(test_who[1], iDomConst::FREE);
49
4
    test_data_rs232.pointer.ptr_who = test_who;
50
4
    EXPECT_EQ(useful_F::myStaticData->myEventHandler.run("RS232")->howManyEvent(), 0);
51
4
    SerialPi_set_recv_msg("");
52
4
    EXPECT_STREQ(TEST_DATA::serial_b.c_str(),"");
53
4
    Send_Recieve_rs232_thread(&test_data_rs232, "RS232_thread");
54
4
55
4
    EXPECT_STREQ(TEST_DATA::serial_b.c_str(),"");
56
4
    EXPECT_EQ(test_data_rs232.pointer.ptr_who[1], iDomConst::CLOCK);
57
4
    EXPECT_EQ(useful_F::myStaticData->myEventHandler.run("RS232")->howManyEvent(), 1);
58
4
}
59
60
TEST_F(rs232_thread_fixture, send_Recieve_rs232_thread_RS232)
61
4
{
62
4
    useful_F::go_while = true;
63
4
    thread_data_rs232 test_data_rs232;
64
4
    test_data_rs232.BaudRate = "9600";
65
4
    test_data_rs232.portRS232 = "test_port";
66
4
    test_data_rs232.portRS232_clock = "test_port_clock";
67
4
    unsigned int test_who[2] = {iDomConst::RS232, iDomConst::FREE};
68
4
    test_data_rs232.pointer.ptr_who = test_who;
69
4
70
4
    test_data_rs232.pointer.ptr_who[0] = iDomConst::RS232;
71
4
    EXPECT_EQ(test_who[0], iDomConst::RS232);
72
4
    SerialPi_set_recv_msg("OK;");
73
4
    Send_Recieve_rs232_thread(&test_data_rs232,"RS232_thread");
74
4
75
4
    EXPECT_STREQ(TEST_DATA::serial_b.c_str(),"");
76
4
    EXPECT_EQ(test_who[1], iDomConst::RS232);
77
4
}
78
79
TEST_F(rs232_thread_fixture, send_Recieve_rs232_thread_FREE)
80
4
{
81
4
    EXPECT_EQ(useful_F::myStaticData->myEventHandler.run("RS232")->howManyEvent(), 0);
82
4
    useful_F::go_while = true;
83
4
    thread_data_rs232 test_data_rs232;
84
4
    test_data_rs232.BaudRate = "9600";
85
4
    test_data_rs232.portRS232 = "test_port";
86
4
    test_data_rs232.portRS232_clock = "test_port_clock";
87
4
    unsigned int test_who[2] = {iDomConst::FREE, iDomConst::FREE};
88
4
    test_data_rs232.pointer.ptr_who = test_who;
89
4
90
4
    test_data_rs232.pointer.ptr_who[0] = iDomConst::FREE;
91
4
    EXPECT_EQ(test_who[0], iDomConst::FREE);
92
4
    SerialPi_set_recv_msg("TEST;");
93
4
    Send_Recieve_rs232_thread(&test_data_rs232,"RS232_thread");
94
4
95
4
    EXPECT_STREQ(TEST_DATA::serial_b.c_str(),"");
96
4
    EXPECT_EQ(test_who[1], iDomConst::FREE);
97
4
    EXPECT_EQ(useful_F::myStaticData->myEventHandler.run("RS232")->howManyEvent(), 1);
98
4
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/thread_functions/iDom_thread.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "iDom_thread.h"
2
#include "../functions/functions.h"
3
#include <tuple>
4
#include <array>
5
#include <functional>
6
7
std::string iDOM_THREAD::start_thread(const std::string& name,
8
                                      std::function<void(thread_data*,const std::string& threadName)> functionToThread, //void(fn)(thread_data),
9
                                      thread_data* my_data,
10
                                      int thread_socket)
11
20
{
12
20
    int freeSlotID = iDOM_THREAD::findFreeThreadSlot(my_data->main_THREAD_arr);
13
20
14
20
    if ( freeSlotID != -1)
15
16
    {
16
16
        std::size_t it = static_cast<std::size_t>(freeSlotID);
17
16
        my_data->main_THREAD_arr->at(it).thread = std::thread(functionToThread ,my_data, name);
18
16
19
16
        my_data->main_THREAD_arr->at(it).thread_name   = name;
20
16
        my_data->main_THREAD_arr->at(it).thread_ID     = my_data->main_THREAD_arr->at(it).thread.get_id();
21
16
        my_data->main_THREAD_arr->at(it).thread_socket = thread_socket;
22
16
        my_data->main_THREAD_arr->at(it).thread.detach();
23
16
24
16
        log_file_mutex.mutex_lock();
25
16
        log_file_cout << INFO << "watek " << name << " wystartowal "
26
16
                      << my_data->main_THREAD_arr->at(it).thread_ID << std::endl;
27
16
        log_file_mutex.mutex_unlock();
28
16
29
16
        return "DONE - " + name + " STARTED";
30
16
    }
31
4
    return "not free space to new thread";
32
4
}
33
34
std::string iDOM_THREAD::start_thread_RS232(const std::string &name,
35
                                            std::function<void (thread_data_rs232 *, const std::string &)> functionToThread,
36
                                            thread_data* my_data,
37
                                            thread_data_rs232 *my_data_rs232,
38
                                            int thread_socket)
39
0
{
40
0
    int freeSlotID = iDOM_THREAD::findFreeThreadSlot(my_data->main_THREAD_arr);
41
0
42
0
    if ( freeSlotID != -1)
43
0
    {
44
0
        std::size_t it = static_cast<std::size_t>(freeSlotID);
45
0
        my_data->main_THREAD_arr->at(it).thread = std::thread(functionToThread ,my_data_rs232, name);
46
0
47
0
        my_data->main_THREAD_arr->at(it).thread_name   = name;
48
0
        my_data->main_THREAD_arr->at(it).thread_ID     = my_data->main_THREAD_arr->at(it).thread.get_id();
49
0
        my_data->main_THREAD_arr->at(it).thread_socket = thread_socket;
50
0
        my_data->main_THREAD_arr->at(it).thread.detach();
51
0
52
0
        log_file_mutex.mutex_lock();
53
0
        log_file_cout << INFO << "watek " << name << " wystartowal "<< my_data->main_THREAD_arr->at(it).thread_ID << std::endl;
54
0
        log_file_mutex.mutex_unlock();
55
0
56
0
        return "DONE - " + name + " STARTED";
57
0
    }
58
0
    return "not free space to new thread";
59
0
}
60
61
void iDOM_THREAD::stop_thread(const std::string& name,
62
                              thread_data* my_data)
63
52
{
64
52
    try
65
52
    {
66
436
        for (std::size_t i = 0; i< iDomConst::MAX_CONNECTION; ++i)
67
400
        {
68
400
            if (my_data->main_THREAD_arr->at(i).thread_ID == std::this_thread::get_id())
69
16
            {
70
16
                my_data->main_THREAD_arr->at(i).thread_name ="  -empty-  ";
71
16
                my_data->main_THREAD_arr->at(i).thread_ID = std::thread::id();
72
16
                my_data->main_THREAD_arr->at(i).thread_socket = 0;
73
16
                break;
74
16
            }
75
400
        }
76
52
    }
77
52
    catch (std::system_error &e)
78
52
    {
79
0
        log_file_mutex.mutex_lock();
80
0
        log_file_cout << ERROR<< "zlapano wyjatek w watku: " << name << ": " << e.what()<< std::endl;
81
0
        log_file_mutex.mutex_unlock();
82
0
    }
83
52
84
52
    log_file_mutex.mutex_lock();
85
52
    log_file_cout << INFO<< "koniec watku: " <<name << std::endl;
86
52
    log_file_mutex.mutex_unlock();
87
52
}
88
89
void iDOM_THREAD::waitUntilAllThreadEnd(thread_data *my_data)
90
4
{
91
4
    int threadCounter = 0;
92
4
    int counter = 20;
93
4
    do{
94
4
        if (--counter == 0){
95
0
            puts("niedoczekalem sie konca watkow");
96
0
            break;
97
0
        }
98
4
        std::this_thread::sleep_for(std::chrono::milliseconds(1500));
99
4
        threadCounter = 0;
100
44
        for(auto i = my_data->main_THREAD_arr->begin(); i < my_data->main_THREAD_arr->end(); ++i)
101
40
        {
102
40
            threadCounter += i->thread_socket;
103
40
            if (i->thread_socket != 0)
104
0
                std::cout << "thread name: "<< i->thread_name << std::endl;
105
40
        }
106
4
        std::cout << "watki pracuja "<<threadCounter<< std::endl;
107
4
    } while(threadCounter != 0);
108
4
}
109
110
111
int iDOM_THREAD::findFreeThreadSlot(std::array<Thread_array_struc, iDomConst::MAX_CONNECTION> *array)
112
20
{
113
84
    for (std::size_t i = 0; i< array->size(); ++i)
114
80
    {
115
80
        if (array->at(i).thread_socket == 0)
116
16
            return static_cast<int>(i);
117
80
    }
118
20
    puts("return -1");
119
4
    return -1;
120
20
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/src/thread_functions/rs232_thread.h
Line
Count
Source (jump to first uncovered line)
1
#ifndef RS232_THREAD_H
2
#define RS232_THREAD_H
3
4
#include "../c_connection/c_connection.h"
5
#include "../TASKER/tasker.h"
6
#include "../SerialPi/serialpi.h"
7
#include "../thread_functions/iDom_thread.h"
8
9
//////////// watek wysylajacy/obdbierajacy dane z portu RS232 ////////
10
16
void Send_Recieve_rs232_thread (thread_data_rs232 *data_rs232, const std::string& threadName){
11
16
12
16
    SerialPi serial_ardu(data_rs232->portRS232);
13
16
    serial_ardu.begin( std::stoi( data_rs232->BaudRate));
14
16
15
16
    log_file_mutex.mutex_lock();
16
16
    log_file_cout << INFO <<"otwarcie portu RS232 " << data_rs232->portRS232 << " " <<data_rs232->BaudRate<<std::endl;
17
16
    log_file_mutex.mutex_unlock();
18
16
19
16
    SerialPi serial_ardu_clock(data_rs232->portRS232_clock);
20
16
    serial_ardu_clock.begin( std::stoi( data_rs232->BaudRate));
21
16
22
16
    log_file_mutex.mutex_lock();
23
16
    log_file_cout << INFO <<"otwarcie portu RS232_clock " << data_rs232->portRS232_clock <<" "<< data_rs232->BaudRate <<std::endl;
24
16
    log_file_mutex.mutex_unlock();
25
16
26
16
    /////////////////////////////////////////////////// RESET ARDUINO AFTER RESTART ////////////////////////////////
27
16
    puts("restart arduino\n");
28
16
    //C_connection::mutex_who.lock();
29
16
    {
30
16
        std::lock_guard<std::mutex> lockWho(useful_F::mutex_who);
31
16
        buffer = "reset:00;";
32
16
        serial_ardu.print(buffer.c_str());
33
16
    }
34
16
    //C_connection::mutex_who.unlock();
35
16
    //puts("test testo po lock");
36
16
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
37
16
    while(useful_F::go_while)
38
16
    {
39
16
        std::this_thread::sleep_for( std::chrono::milliseconds(50));
40
16
        //puts("test testo po lock");
41
16
        { //mutex who
42
16
            std::lock_guard<std::mutex> lockWho(useful_F::mutex_who);
43
16
44
16
            if(data_rs232->pointer.ptr_who[0] == iDomConst::RS232)
45
4
            {
46
4
                std::lock_guard<std::mutex> lockBuf(useful_F::mutex_buf);
47
4
                data_rs232->pointer.ptr_who[0] = data_rs232->pointer.ptr_who[1];
48
4
                data_rs232->pointer.ptr_who[1] = iDomConst::RS232;
49
4
                serial_ardu.print(buffer.c_str());
50
4
51
4
                buffer.erase();
52
4
53
12
                while(useful_F::go_while){
54
12
                    if(serial_ardu.available()>0){
55
12
                        buffer += serial_ardu.read();
56
12
                    }
57
12
                    if(buffer[buffer.size()-1] == ';')
58
4
                    {
59
4
                        buffer.erase(buffer.end()-1);
60
4
                        break;
61
4
                    }
62
12
                }
63
4
#ifdef BT_TEST
64
4
                useful_F::go_while = false;
65
4
                return;
66
4
#endif
67
4
            }
68
12
            else if(data_rs232->pointer.ptr_who[0] == iDomConst::CLOCK)
69
8
            {
70
8
                std::lock_guard<std::mutex> lockBuf(useful_F::mutex_buf);
71
8
                data_rs232->pointer.ptr_who[0] = data_rs232->pointer.ptr_who[1];
72
8
                data_rs232->pointer.ptr_who[1] = iDomConst::CLOCK;
73
8
                serial_ardu_clock.print(buffer.c_str());
74
8
75
8
                buffer.erase();
76
8
77
8
                while(useful_F::go_while){
78
8
                    if(serial_ardu_clock.available()>0)
79
4
                    {
80
4
                        buffer += serial_ardu_clock.read();
81
4
                        buffer += serial_ardu_clock.read();
82
4
                        serial_ardu_clock.flush();
83
4
                        break;
84
4
                    }
85
4
                    else
86
4
                    {
87
4
                        puts("w buforze serial_ardu_clock nie ma avaiable ");
88
4
89
4
                        useful_F::myStaticData->myEventHandler.run("RS232")
90
4
                                ->addEvent("w buforze serial_ardu_clock nie ma avaiable ");
91
4
                        break;
92
4
                    }
93
8
                }
94
8
#ifdef BT_TEST
95
8
                useful_F::go_while = false;
96
8
                return;
97
8
#endif
98
8
            }
99
4
            else if(data_rs232->pointer.ptr_who[0] == iDomConst::FREE)
100
4
            {
101
4
                std::string bufor = "";
102
4
                if(serial_ardu.available()>0) {
103
4
104
20
                    while (useful_F::go_while){
105
20
                        // std::cout << "serial_ardu.available(): "<<serial_ardu.available()<<std::endl;
106
20
                        if(serial_ardu.available()>0){
107
20
                            char t = serial_ardu.read();
108
20
                            // std::cout << "t: "<<t<<std::endl;
109
20
                            if(t == ';'){
110
4
                                serial_ardu.flush();
111
4
                                break;
112
4
                            }
113
16
                            else{
114
16
                                bufor.push_back(t);
115
16
                            }
116
20
                        }
117
20
                    }
118
4
                    useful_F::myStaticData->myEventHandler.run("RS232")->addEvent(bufor);
119
4
120
4
                }
121
4
#ifdef BT_TEST
122
4
                useful_F::go_while = false;
123
4
                return;
124
4
#endif
125
4
            }
126
16
127
16
        }
128
16
    }
129
16
    iDOM_THREAD::stop_thread(threadName, useful_F::myStaticData);
130
0
}
131
#endif // RS232_THREAD_H
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/test/iDom_TESTs-CMAKE/main.cpp
Line
Count
Source (jump to first uncovered line)
1
#include <iostream>
2
#include <gtest/gtest.h>
3
#include <gmock/gmock.h>
4
#include <gconv.h>
5
#include <fstream>
6
#include <sstream>
7
#include <test_data.h>
8
#include <../../../../libs/useful/useful.h>
9
#include "../../../../src/SerialPi/serialpi.h"
10
#include "../../../../src/functions/functions.h"
11
12
10
#define log_file_cout f_log //std::cout   zmien f_log na std::cout  i bedzie wypisywac na
13
std::string  _logfile = "/mnt/ramdisk/iDom_log_BT.log";
14
15
Logger log_file_mutex(_logfile);
16
17
18
std::string TEST_DATA::return_send_to_arduino = "-2:-2";
19
std::string TEST_DATA::return_httpPost = "ok.\n";
20
std::string TEST_DATA::return_httpPost_expect = "";
21
std::string TEST_DATA::return_viber_msg = "";
22
std::string TEST_DATA::serial_b = "NULL";
23
std::string TEST_DATA::serial_sended = "NULL";
24
std::string TEST_DATA::LCD_print = "NULL";
25
int TEST_DATA::test_pin = 0;
26
int TEST_DATA::runLinuxCommandReturn = 0;
27
28
unsigned int Clock::m_BT_H = 0;
29
unsigned int Clock::m_BT_M = 0;
30
31
28
void SerialPi_set_recv_msg(const std::string& m){
32
28
    TEST_DATA::serial_b = m;
33
28
}
34
35
40
void SerialPi_set_serial_sended(const std::string& m){
36
40
    TEST_DATA::serial_sended = m;
37
40
}
38
240
SerialPi::SerialPi(const std::string& a):m_serial_port(10){
39
240
    std::cout << "SerialPi() addres: " << a << std::endl;
40
240
}
41
240
SerialPi::~SerialPi(){
42
240
    std::cout << "~SerialPi()" << std::endl;
43
240
}
44
45
40
void SerialPi::print(const std::string& msg){
46
40
    std::cout << "SerialPi::print() msg: " << msg << std::endl;
47
40
    SerialPi_set_serial_sended(msg);
48
40
}
49
50
51
36
void SerialPi::begin(int serialSpeed){
52
36
    std::cout << "SerialPi::int() serialSpeed: " << serialSpeed << std::endl;
53
36
}
54
55
12
void SerialPi::flush(){
56
12
    std::cout << "SerialPi::flush()" << std::endl;
57
12
    TEST_DATA::serial_b.clear();
58
12
}
59
60
60
int SerialPi::available(){
61
60
    std::cout << "SerialPi::available() " << TEST_DATA::serial_b.size() << std::endl;
62
60
    return static_cast<int>(TEST_DATA::serial_b.size());
63
60
}
64
65
156
char SerialPi::read(){
66
156
    char r = TEST_DATA::serial_b.at(0);
67
156
    TEST_DATA::serial_b.erase(0,1);
68
156
    std::cout << "SerialPi::read(): "<<r<< std::endl;
69
156
    return r;
70
156
}
71
72
80
void digitalWrite(int pin, int mode){}
73
74
void setReturnPinState(int i)
75
28
{
76
28
    TEST_DATA::test_pin = i;
77
28
}
78
79
784
viber_API::viber_API(){}
80
784
void viber_API::setAccessToken(const std::string& accessToken){}
81
784
void viber_API::setURL(const std::string& url){}
82
792
void viber_API::setAvatar(const std::string& avatar){}
83
std::string viber_API::sendViberMSG(const std::string& msg,
84
                                    const std::string& receiver,
85
                                    const std::string& senderName,
86
                                    const std::string& accessToken,
87
44
                                    const std::string& url){
88
44
89
44
    std::cout << "sendViberMSG() "<< msg <<" to: "<< receiver << std::endl;
90
44
    TEST_DATA::return_viber_msg = msg;
91
44
    return"{\"message_status\":\"ok\"}";
92
44
}
93
std::string viber_API::sendViberPicture(const std::string& msg,
94
                                        const std::string& image,
95
                                        const std::string& receiver,
96
                                        const std::string& senderName,
97
                                        const std::string& accessToken ,
98
100
                                        const std::string& url){
99
100
    std::cout << "sendViberPicture() "<< msg <<" to: "<< receiver << std::endl;
100
100
    TEST_DATA::return_viber_msg = msg;
101
100
    return"{\"message_status\":\"ok\"}";
102
100
}
103
784
FACEBOOK_API::FACEBOOK_API(){}
104
std::string FACEBOOK_API::postTxtOnWall(const std::string& msg,
105
0
                                        const std::string& accessToken ){return "";}
106
std::string FACEBOOK_API::postPhotoOnWall(const std::string& url,
107
                                          const std::string& msg ,
108
8
                                          const std::string& accessToken ){return "";}
109
784
void FACEBOOK_API::setAccessToken(const std::string& token){}
110
111
136
void LCD_c::set_lcd_STATE(int i){}
112
696
void LCD_c::printString(bool clear, int col, int row, const std::string& str){
113
696
    std::cout << "LCD_c::printString() "<< str << std::endl;
114
696
    TEST_DATA::LCD_print = str;
115
696
}
116
117
60
std::string useful_F_libs::httpPost(const std::string& url, int timeoutSeconds){
118
60
119
60
    std::cout << "url: "<< url << " return "<< TEST_DATA::return_httpPost << "|"<< std::endl;
120
60
    TEST_DATA::return_httpPost_expect = "httpPost";
121
60
    return TEST_DATA::return_httpPost;
122
60
}
123
16
std::string useful_F_libs::httpPost(const std::string& url){
124
16
    CURL *curl;
125
16
    CURLcode res;
126
16
    std::string readBuffer;
127
16
    curl = curl_easy_init();
128
16
129
16
    if(curl) {
130
16
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
131
16
        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
132
16
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, useful_F_libs::WriteCallback);
133
16
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
134
16
        res = curl_easy_perform(curl);
135
16
        /* Check for errors */
136
16
        if(res != CURLE_OK)
137
0
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
138
0
                    curl_easy_strerror(res));
139
16
140
16
        /* always cleanup */
141
16
        curl_easy_cleanup(curl);
142
16
    }
143
16
    curl_global_cleanup();
144
16
145
16
    return readBuffer;
146
16
}
147
148
28
int digitalRead(int pin){ return TEST_DATA::test_pin; }
149
150
class test_433
151
{
152
public:
153
    std::string config433 = "{ \"BUTTON\": { \"locker\": { \"OFF\": \"NULL\", \"ON\": \"NULL\", \"id\": \"01e7be\", \"name\": \"locker\", \"type\": \"BUTTON\" } }, \"SWITCH\": { \"A\": { \"OFF\": \"10;TriState;0280aa;0;OFF\", \"ON\": \"10;TriState;0280aa;0;ON\", \"id\": \"1444\", \"name\": \"A\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\",\"lock\": \"null\", \"unlock\": \"null\", \"type\": \"SWITCH\" }, \"ALARM\": { \"OFF\": \"dummyOFF\", \"ON\": \"dummyON\", \"id\": \"1223\", \"name\": \"ALARM\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\",\"lock\": \"null\", \"unlock\": \"null\", \"type\": \"SWITCH\" }, \"B\": { \"OFF\": \"10;TriState;02822a;0;OFF\", \"ON\": \"10;TriState;02822a;0;ON\", \"id\": \"1445\", \"name\": \"B\", \"on15sec\": \"10;TriState;02822a;0;ON\", \"sunrise\": \"ON\", \"sunset\": \"OFF\", \"lock\": \"null\", \"unlock\": \"null\",\"type\": \"SWITCH\" }, \"C\": { \"OFF\": \"null\", \"ON\": \"null\", \"id\": \"1446\", \"name\": \"C\", \"on15sec\": \"null\", \"sunrise\": \"OFF\", \"sunset\": \"ON\", \"lock\": \"null\", \"unlock\": \"null\",\"type\": \"SWITCH\" }, \"listwa\": { \"OFF\": \"10;Kaku;0ad04d;15;OFF\", \"ON\": \"10;Kaku;0ad04d;15;ON\", \"id\": \"1450\", \"name\": \"listwa\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\",\"lock\": \"OFF\", \"unlock\": \"ON\", \"type\": \"SWITCH\" } }, \"WEATHER\": { \"first\": { \"OFF\": \"NULL\", \"ON\": \"NULL\", \"id\": \"0704\", \"name\": \"first\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\", \"type\": \"WEATHER\" } } }";
154
    std::string config433_fake = "{ \"BUTTON\": { \"locker\": { \"OFF\": \"NULL\", \"ON\": \"NULL\", \"id\": \"01e7be\", \"name\": \"locker\",  \"type\": \"BUTTON\" } }, \"SWITCH\": { \"A\": { \"OFF\": \"10;TriState;0280aa;0;OFF\", \"ON\": \"10;TriState;0280aa;0;ON\", \"id\": \"1444\", \"name\": \"A\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\",\"lock\": \"null\", \"unlock\": \"null\", \"type\": \"SWITCH\" }, \"ALARM\": { \"OFF\": \"dummyOFF\", \"ON\": \"dummyON\", \"id\": \"1223\", \"name\": \"ALARM\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\",\"lock\": \"null\", \"unlock\": \"null\", \"type\": \"SWITCH\" }, \"B\": { \"OFF\": \"10;TriState;02822a;0;OFF\", \"ON\": \"10;TriState;02822a;0;ON\", \"id\": \"1445\", \"name\": \"B\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\", \"lock\": \"null\", \"unlock\": \"null\",\"type\": \"SWITCH\" }, \"C\": { \"OFF\": \"10;TriState;02828a;0;OFF\", \"ON\": \"10;TriState;02828a;0;ON\", \"id\": \"1446\", \"name\": \"C\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\",\"lock\": \"null\", \"unlock\": \"null\", \"type\": \"SWITCH\" }, \"listwa\": { \"OFF\": \"10;Kaku;0ad04d;15;OFF\", \"ON\": \"10;Kaku;0ad04d;15;ON\", \"id\": \"1450\", \"name\": \"listwa\", \"on15sec\": \"null\", \"sunrise\": \"NULL\", \"sunset\": \"NULL\",\"lock\": \"OFF\", \"unlock\": \"null\", \"type\": \"SWITCH\" } } } }";
155
156
    void makeFile(const std::string& path)
157
1
    {
158
1
        std::ofstream o(path);
159
1
        o << config433 ;
160
1
    }
161
    void makeFileFake(const std::string& path)
162
1
    {
163
1
        std::ofstream o(path);
164
1
        o << config433_fake ;
165
1
    }
166
};
167
168
int main(int argc, char **argv)
169
1
{
170
1
    test_433 t;
171
1
    t.makeFile("/mnt/ramdisk/433_eq_conf.json");
172
1
    t.makeFileFake("/mnt/ramdisk/433_eq_conf_fake.json");
173
1
174
1
    std::fstream ofs;
175
1
    ofs.open(_logfile, std::ios::out | std::ios::trunc);
176
1
    ofs.close(); //Using microsoft incremental linker version 14
177
1
178
1
    pthread_mutex_init(&Logger::mutex_log, NULL);
179
1
180
1
    log_file_mutex.mutex_lock();
181
1
    log_file_cout << std::endl<< std::endl<<"============================================"
182
1
                  << std::endl<< std::endl<< std::endl<< INFO << "START BT "<< std::endl;
183
1
    log_file_mutex.mutex_unlock();
184
1
185
1
    ::testing::InitGoogleTest( &argc, argv );
186
1
    //::testing::GTEST_FLAG(filter) = "functions_fixture.sleepThread";
187
1
    //::testing::GTEST_FLAG(filter) = "event_counter_fixture.getLast1minNumberEvent";
188
1
    //::testing::GTEST_FLAG(filter) = "command433MHz_Class_fixture.*)";
189
1
    auto ret = RUN_ALL_TESTS();
190
1
    pthread_mutex_destroy(&Logger::mutex_log);
191
1
192
1
    const char * PROG_INFO = " Basic TEST iDomServer: " __DATE__ ", " __TIME__;
193
1
    std::cout << "wersja " <<PROG_INFO <<" "<< GIT_BRANCH <<" " << GIT_COMMIT_HASH << std::endl;
194
1
    return ret;
195
1
}
/mnt/e/PROGRAMOWANIE/malina/iDom_server_OOP/test/iDom_TESTs-CMAKE/wiringPi.h
Line
Count
Source
1
48
#define LOW      0
2
32
#define HIGH  1
3
int digitalRead (int pin) ;
4
void digitalWrite (int pin, int value) ;